// lib/storage/notebook_manifest.dart
//
// OneNote-style notebook container: a vault folder with `notebook.json` that
// lists members (blank notes + imported PDF/PPTX/DOCX). Each member still uses
// its own sidecar; this file is only the table of contents.

import 'dart:convert';
import 'dart:io';

import 'package:path/path.dart' as p;

/// Filename of the notebook container manifest inside a vault folder.
const String kNotebookManifestName = 'notebook.json';

/// Default annotation font family (matches app UI theme).
const String kAnnotationFontFamily = 'IBM Plex Sans';

/// Kind of a notebook member.
enum NotebookMemberKind {
  note,
  pdf,
  pptx,
  ppt,
  docx,
}

NotebookMemberKind? notebookMemberKindFromExt(String ext) {
  switch (ext.toLowerCase()) {
    case 'pdf':
      return NotebookMemberKind.pdf;
    case 'pptx':
      return NotebookMemberKind.pptx;
    case 'ppt':
      return NotebookMemberKind.ppt;
    case 'docx':
      return NotebookMemberKind.docx;
    case 'note':
    case 'notebook':
      return NotebookMemberKind.note;
    default:
      return null;
  }
}

String notebookMemberKindToExt(NotebookMemberKind kind) => switch (kind) {
      NotebookMemberKind.note => 'note',
      NotebookMemberKind.pdf => 'pdf',
      NotebookMemberKind.pptx => 'pptx',
      NotebookMemberKind.ppt => 'ppt',
      NotebookMemberKind.docx => 'docx',
    };

/// One page/section inside a notebook container.
class NotebookMember {
  const NotebookMember({
    required this.id,
    required this.kind,
    required this.relativePath,
    required this.title,
  });

  final String id;
  final NotebookMemberKind kind;

  /// Path relative to the notebook folder (POSIX separators preferred).
  final String relativePath;

  final String title;

  Map<String, dynamic> toJson() => {
        'id': id,
        'kind': kind.name,
        'path': relativePath,
        'title': title,
      };

  factory NotebookMember.fromJson(Map<String, dynamic> json) {
    final kindName = (json['kind'] as String?) ?? 'note';
    final kind = NotebookMemberKind.values.firstWhere(
      (k) => k.name == kindName,
      orElse: () => NotebookMemberKind.note,
    );
    return NotebookMember(
      id: (json['id'] as String?) ?? '',
      kind: kind,
      relativePath: (json['path'] as String?) ?? '',
      title: (json['title'] as String?) ?? '',
    );
  }

  NotebookMember copyWith({String? title, String? relativePath}) =>
      NotebookMember(
        id: id,
        kind: kind,
        relativePath: relativePath ?? this.relativePath,
        title: title ?? this.title,
      );
}

/// Table of contents for a multi-document notebook folder.
class NotebookManifest {
  const NotebookManifest({
    required this.title,
    required this.members,
    this.version = 1,
  });

  final int version;
  final String title;
  final List<NotebookMember> members;

  Map<String, dynamic> toJson() => {
        'version': version,
        'title': title,
        'members': members.map((m) => m.toJson()).toList(),
      };

  factory NotebookManifest.fromJson(Map<String, dynamic> json) {
    final raw = (json['members'] as List<dynamic>?) ?? const [];
    return NotebookManifest(
      version: (json['version'] as num?)?.toInt() ?? 1,
      title: (json['title'] as String?) ?? '',
      members: [
        for (final e in raw)
          NotebookMember.fromJson(e as Map<String, dynamic>),
      ],
    );
  }

  NotebookManifest copyWith({
    String? title,
    List<NotebookMember>? members,
  }) =>
      NotebookManifest(
        version: version,
        title: title ?? this.title,
        members: members ?? this.members,
      );

  static File fileIn(String folderPath) =>
      File(p.join(folderPath, kNotebookManifestName));

  static Future<NotebookManifest?> read(String folderPath) async {
    final file = fileIn(folderPath);
    if (!await file.exists()) return null;
    try {
      final map = jsonDecode(await file.readAsString()) as Map<String, dynamic>;
      return NotebookManifest.fromJson(map);
    } catch (_) {
      return null;
    }
  }

  static Future<void> write(String folderPath, NotebookManifest manifest) async {
    final file = fileIn(folderPath);
    await file.writeAsString(
      const JsonEncoder.withIndent('  ').convert(manifest.toJson()),
    );
  }
}
