import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../models/note.dart';
import '../services/vault_search_index.dart';
import 'document_provider.dart' show vaultServiceProvider;

/// The search index, rebuilt by SCANNING the vault sidecars (the source of
/// truth) — NOT the demoted SQLite cache (Phase 6, §B/§F). Bumping
/// [searchIndexEpochProvider] (e.g. after an import or note edit) invalidates
/// this provider so the next read re-scans the vault from disk.
final vaultSearchIndexProvider = FutureProvider<VaultSearchIndex>((ref) async {
  ref.watch(searchIndexEpochProvider);
  final vault = await ref.watch(vaultServiceProvider.future);
  final index = VaultSearchIndex(vault);
  await index.rebuild();
  return index;
});

/// Bump to force the search index to rebuild from disk (e.g. after an import).
final searchIndexEpochProvider = StateProvider<int>((ref) => 0);

final searchQueryProvider = StateProvider<String>((ref) => '');

/// A search result that can be either a note hit or a document hit.
sealed class SearchResult {
  const SearchResult();
}

class NoteSearchHit extends SearchResult {
  final Note note;
  final String snippet;
  const NoteSearchHit({required this.note, this.snippet = ''});
}

class DocumentSearchHit extends SearchResult {
  final String documentId;
  final String filename;
  final String filePath;
  final int pageNumber;
  final String snippet;
  const DocumentSearchHit({
    required this.documentId,
    required this.filename,
    required this.filePath,
    required this.pageNumber,
    this.snippet = '',
  });
}

final searchResultsProvider = FutureProvider<List<SearchResult>>((ref) async {
  final query = ref.watch(searchQueryProvider);
  if (query.trim().isEmpty) return [];

  final index = await ref.watch(vaultSearchIndexProvider.future);

  final hits = await index.search(query);

  final results = <SearchResult>[];
  for (final hit in hits) {
    final entry = hit.entry;
    final snippet = hit.snippet.text;
    if (entry.isNote) {
      // Construct a lightweight Note whose id is the synthetic note path so
      // PenNoteScreen re-keys the right sidecar on open. Strokes are hydrated
      // lazily by the editor; the search list only needs id/title.
      final now = DateTime.now();
      results.add(
        NoteSearchHit(
          note: Note(
            id: entry.openPath,
            title: entry.title,
            createdAt: now,
            updatedAt: now,
          ),
          snippet: snippet,
        ),
      );
    } else {
      results.add(
        DocumentSearchHit(
          documentId: entry.id,
          filename: entry.title,
          filePath: entry.openPath,
          // The scan-based index matches whole-notebook text, not per-page, so
          // the document opens at its first page.
          pageNumber: 0,
          snippet: snippet,
        ),
      );
    }
  }

  return results;
});
