import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../models/note.dart';
import '../providers/search_provider.dart';
import 'note_editor_screen.dart';
import 'pdf_annotator_screen.dart';

class SearchScreen extends ConsumerStatefulWidget {
  const SearchScreen({super.key});

  @override
  ConsumerState<SearchScreen> createState() => _SearchScreenState();
}

class _SearchScreenState extends ConsumerState<SearchScreen> {
  final TextEditingController _controller = TextEditingController();
  Timer? _debounce;

  @override
  void initState() {
    super.initState();
    _controller.addListener(() => setState(() {}));
  }

  @override
  void dispose() {
    _debounce?.cancel();
    _controller.dispose();
    super.dispose();
  }

  void _onQueryChanged(String value) {
    _debounce?.cancel();
    _debounce = Timer(const Duration(milliseconds: 300), () {
      ref.read(searchQueryProvider.notifier).state = value.trim();
    });
  }

  @override
  Widget build(BuildContext context) {
    final results = ref.watch(searchResultsProvider);

    return Scaffold(
      appBar: AppBar(
        title: TextField(
          controller: _controller,
          autofocus: true,
          decoration: const InputDecoration(
            hintText: 'Search notes and documents...',
            border: InputBorder.none,
            hintStyle: TextStyle(color: Colors.grey),
          ),
          onChanged: _onQueryChanged,
          onSubmitted: (value) {
            _debounce?.cancel();
            ref.read(searchQueryProvider.notifier).state = value.trim();
          },
        ),
        actions: [
          if (_controller.text.isNotEmpty)
            IconButton(
              icon: const Icon(Icons.clear),
              onPressed: () {
                _controller.clear();
                ref.read(searchQueryProvider.notifier).state = '';
              },
            ),
        ],
      ),
      body: results.when(
        loading: () => const Center(child: CircularProgressIndicator()),
        error: (e, _) => Center(child: Text('Search error: $e')),
        data: (hits) {
          final query = ref.watch(searchQueryProvider);
          if (query.isEmpty) {
            return const Center(
              child: Text(
                'Type to search your notes and documents',
                style: TextStyle(color: Colors.grey),
              ),
            );
          }
          if (hits.isEmpty) {
            return Center(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Icon(
                    Icons.search_off,
                    size: 64,
                    color: Theme.of(context).colorScheme.onSurfaceVariant,
                  ),
                  const SizedBox(height: 16),
                  Text(
                    'No results for "$query"',
                    style: Theme.of(context).textTheme.bodyLarge?.copyWith(
                      color: Theme.of(context).colorScheme.onSurfaceVariant,
                    ),
                  ),
                ],
              ),
            );
          }

          final noteHits = hits.whereType<NoteSearchHit>().toList();
          final docHits = hits.whereType<DocumentSearchHit>().toList();

          return ListView(
            children: [
              if (noteHits.isNotEmpty) ...[
                Padding(
                  padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
                  child: Text(
                    'Notes',
                    style: Theme.of(context).textTheme.titleSmall?.copyWith(
                      fontWeight: FontWeight.bold,
                      color: Theme.of(context).colorScheme.primary,
                    ),
                  ),
                ),
                ...noteHits.map(
                  (hit) => _NoteSearchResultTile(note: hit.note, query: query),
                ),
              ],
              if (docHits.isNotEmpty) ...[
                Padding(
                  padding: const EdgeInsets.fromLTRB(16, 16, 16, 4),
                  child: Text(
                    'Documents',
                    style: Theme.of(context).textTheme.titleSmall?.copyWith(
                      fontWeight: FontWeight.bold,
                      color: Theme.of(context).colorScheme.primary,
                    ),
                  ),
                ),
                ...docHits.map(
                  (hit) => _DocumentSearchResultTile(
                    documentId: hit.documentId,
                    filename: hit.filename,
                    filePath: hit.filePath,
                    pageNumber: hit.pageNumber,
                    snippet: hit.snippet,
                    query: query,
                  ),
                ),
              ],
            ],
          );
        },
      ),
    );
  }
}

class _NoteSearchResultTile extends StatelessWidget {
  final Note note;
  final String query;

  const _NoteSearchResultTile({required this.note, required this.query});

  @override
  Widget build(BuildContext context) {
    final d = note.updatedAt;
    final dateStr =
        '${d.month}/${d.day}/${d.year} ${d.hour}:${d.minute.toString().padLeft(2, '0')}';

    return ListTile(
      leading: const Icon(Icons.edit_note),
      title: _HighlightedText(text: note.title, query: query),
      subtitle: Text(
        '${note.strokes.length} stroke${note.strokes.length == 1 ? '' : 's'} · $dateStr',
        style: Theme.of(context).textTheme.bodySmall,
      ),
      onTap: () {
        Navigator.of(
          context,
        ).push(MaterialPageRoute(builder: (_) => NoteEditorScreen(note: note)));
      },
    );
  }
}

class _DocumentSearchResultTile extends StatelessWidget {
  final String documentId;
  final String filename;
  final String filePath;
  final int pageNumber;
  final String snippet;
  final String query;

  const _DocumentSearchResultTile({
    required this.documentId,
    required this.filename,
    required this.filePath,
    required this.pageNumber,
    required this.snippet,
    required this.query,
  });

  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: const Icon(Icons.picture_as_pdf, color: Colors.red),
      title: _HighlightedText(text: filename, query: query),
      subtitle: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'Page ${pageNumber + 1}',
            style: Theme.of(context).textTheme.bodySmall,
          ),
          if (snippet.isNotEmpty)
            _HighlightedText(text: snippet, query: query, maxLines: 2),
        ],
      ),
      onTap: () {
        Navigator.of(context).push(
          MaterialPageRoute(
            builder: (_) =>
                PdfAnnotatorScreen(filePath: filePath, initialPage: pageNumber),
          ),
        );
      },
    );
  }
}

/// Highlights matching portions of [text] that match [query].
class _HighlightedText extends StatelessWidget {
  final String text;
  final String query;
  final int maxLines;

  const _HighlightedText({
    required this.text,
    required this.query,
    this.maxLines = 1,
  });

  @override
  Widget build(BuildContext context) {
    if (query.isEmpty || text.isEmpty) {
      return Text(text, maxLines: maxLines, overflow: TextOverflow.ellipsis);
    }

    final lowerText = text.toLowerCase();
    final lowerQuery = query.toLowerCase();
    final spans = <TextSpan>[];
    int start = 0;

    while (true) {
      final index = lowerText.indexOf(lowerQuery, start);
      if (index < 0) {
        if (start < text.length) {
          spans.add(TextSpan(text: text.substring(start)));
        }
        break;
      }
      if (index > start) {
        spans.add(TextSpan(text: text.substring(start, index)));
      }
      spans.add(
        TextSpan(
          text: text.substring(index, index + query.length),
          style: TextStyle(
            fontWeight: FontWeight.bold,
            backgroundColor: Theme.of(context).colorScheme.primaryContainer,
          ),
        ),
      );
      start = index + query.length;
    }

    return RichText(
      maxLines: maxLines,
      overflow: TextOverflow.ellipsis,
      text: TextSpan(
        style: DefaultTextStyle.of(context).style,
        children: spans,
      ),
    );
  }
}
