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

import 'package:flutter/material.dart';
import 'package:flutter/services.dart' hide UndoManager;
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
import 'package:uuid/uuid.dart';

import '../models/bookmark.dart';
import '../models/document.dart';
import '../models/ink_stroke.dart';
import '../models/pen_tool.dart';
import '../models/pressure_curve.dart';
import '../services/camera_service.dart';
import '../services/database_service.dart';
import '../services/pdf_service.dart';
import '../services/thumbnail_service.dart';
import '../services/undo_manager.dart';
import '../utils/stroke_stabilizer.dart';
import '../widgets/annotation_toolbar.dart';
import '../widgets/ink_canvas.dart';
import '../widgets/page_thumbnail_sidebar.dart';
import '../widgets/pdf_annotation_layer.dart';
import 'pdf_text_search.dart';
import 'split_view_screen.dart';

const _uuid = Uuid();

/// Actions available in the AppBar overflow menu.
enum _OverflowAction { pageManagement, cameraInsert, export }

/// Full-screen PDF viewer with ink annotation overlay.
///
/// Displays a PDF page-by-page with a transparent [PdfAnnotationLayer]
/// on top for pen/marker/eraser annotations. Annotations are stored
/// per page in normalized [0, 1] coordinates and exported via [PdfService].
/// Annotations and bookmarks are persisted to the database.
class PdfAnnotatorScreen extends StatefulWidget {
  final String filePath;
  final int initialPage;

  const PdfAnnotatorScreen({
    super.key,
    required this.filePath,
    this.initialPage = 0,
  });

  @override
  State<PdfAnnotatorScreen> createState() => _PdfAnnotatorScreenState();
}

class _PdfAnnotatorScreenState extends State<PdfAnnotatorScreen> {
  final PdfService _pdfService = PdfService();
  final CameraService _cameraService = CameraService();
  final PdfViewerController _viewerController = PdfViewerController();
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  int _currentPage = 0;
  int _pageCount = 0;
  int _pdfMutationVersion = 0;
  String _fileName = '';
  PenTool _currentTool = PenTool.pen;
  Color _currentColor = Colors.black;
  double _currentStrokeWidth = 2.0;
  bool _filled = false;
  PressureCurveType _pressureCurveType = PressureCurveType.linear;
  StabilizationLevel _stabilizationLevel = StabilizationLevel.none;
  InteractionMode _interactionMode = InteractionMode.draw;
  double _zoomLevel = 1.0;
  bool _showThumbnails = false;

  String? _currentDocumentId;
  final Map<int, UndoManager> _undoManagers = {};
  final Map<int, List<InkStroke>> _annotations = {};

  List<Bookmark> _bookmarks = [];

  @override
  void initState() {
    super.initState();
    _currentPage = widget.initialPage;
    _loadPdfInfo();
  }

  Future<void> _loadPdfInfo() async {
    final info = await _pdfService.getPdfInfo(widget.filePath);
    final count = await _pdfService.getPageCount(widget.filePath);
    if (mounted) {
      setState(() {
        _fileName = info['fileName'] as String;
        _pageCount = count;
      });
      await _ensureDocumentExists();
      await _loadAllAnnotations();
      await _loadBookmarks();
    }
  }

  Future<void> _ensureDocumentExists() async {
    final db = await DatabaseService.getInstance();
    final existing = await db.getDocumentByPath(widget.filePath);
    if (existing == null) {
      final now = DateTime.now();
      final newDoc = Document(
        id: _uuid.v4(),
        filename: _fileName,
        docType: 'pdf',
        filePath: widget.filePath,
        pageCount: _pageCount,
        createdAt: now,
        updatedAt: now,
      );
      await db.insertDocument(newDoc);
      _currentDocumentId = newDoc.id;
    } else {
      _currentDocumentId = existing.id;
    }
  }

  Future<void> _loadAllAnnotations() async {
    if (_currentDocumentId == null) return;
    final db = await DatabaseService.getInstance();
    for (int i = 0; i < _pageCount; i++) {
      final json = await db.getAnnotations(_currentDocumentId!, i);
      if (json != null && json.isNotEmpty) {
        final List<dynamic> list = jsonDecode(json) as List<dynamic>;
        _annotations[i] = list
            .map((s) => InkStroke.fromJson(s as Map<String, dynamic>))
            .toList();
        _undoManagers[i] = UndoManager();
        for (final stroke in _annotations[i]!) {
          _undoManagers[i]!.addStroke(stroke);
        }
      }
    }
    if (mounted) setState(() {});
  }

  void _saveCurrentPageAnnotations({int? page}) async {
    if (_currentDocumentId == null) return;
    // Capture the page index and serialize its strokes SYNCHRONOUSLY, before
    // any await. Otherwise a concurrent navigation could change _currentPage
    // while this is suspended, causing the wrong page's data to be saved.
    final targetPage = page ?? _currentPage;
    final documentId = _currentDocumentId!;
    final strokesJson = jsonEncode(
      _annotations[targetPage]?.map((s) => s.toJson()).toList() ?? [],
    );
    final db = await DatabaseService.getInstance();
    await db.saveAnnotations(documentId, targetPage, strokesJson);
  }

  void _onPageChanged(int page) {
    // Save the page we are leaving, not the one we are navigating to.
    _saveCurrentPageAnnotations(page: _currentPage);
    setState(() {
      _currentPage = page;
    });
  }

  UndoManager _getUndoManager(int page) {
    return _undoManagers.putIfAbsent(page, UndoManager.new);
  }

  List<InkStroke> _getCurrentStrokes() {
    return _annotations[_currentPage] ?? [];
  }

  void _onStrokeComplete(InkStroke stroke) {
    setState(() {
      _annotations.putIfAbsent(_currentPage, () => []);
      _annotations[_currentPage]!.add(stroke);
      _getUndoManager(_currentPage).addStroke(stroke);
    });
    _saveCurrentPageAnnotations();
  }

  void _onErase(String strokeId, List<InkStroke> replacements) {
    setState(() {
      final pageStrokes = _annotations[_currentPage];
      if (pageStrokes == null) return;
      final original = pageStrokes.where((s) => s.id == strokeId).firstOrNull;
      if (original != null) {
        _getUndoManager(
          _currentPage,
        ).removeStroke(original, replacements: replacements);
        _annotations[_currentPage] = _getUndoManager(
          _currentPage,
        ).currentStrokes.toList();
      }
    });
    _saveCurrentPageAnnotations();
  }

  void _undo() {
    setState(() {
      _getUndoManager(_currentPage).undo();
      _annotations[_currentPage] = _getUndoManager(
        _currentPage,
      ).currentStrokes.toList();
    });
    _saveCurrentPageAnnotations();
  }

  void _redo() {
    setState(() {
      _getUndoManager(_currentPage).redo();
      _annotations[_currentPage] = _getUndoManager(
        _currentPage,
      ).currentStrokes.toList();
    });
    _saveCurrentPageAnnotations();
  }

  // -- Bookmarks --

  bool get _isCurrentPageBookmarked =>
      _bookmarks.any((b) => b.pageNumber == _currentPage);

  Future<void> _loadBookmarks() async {
    if (_currentDocumentId == null) return;
    final db = await DatabaseService.getInstance();
    final bookmarks = await db.getBookmarks(_currentDocumentId!);
    if (mounted) {
      setState(() {
        _bookmarks = bookmarks;
      });
    }
  }

  Future<void> _toggleBookmark() async {
    if (_currentDocumentId == null) return;
    final db = await DatabaseService.getInstance();

    if (_isCurrentPageBookmarked) {
      final existing = _bookmarks.firstWhere(
        (b) => b.pageNumber == _currentPage,
      );
      await db.deleteBookmark(existing.id);
      setState(() {
        _bookmarks.removeWhere((b) => b.id == existing.id);
      });
    } else {
      final label = await _showBookmarkDialog();
      if (label == null) return;

      final bookmark = Bookmark(
        id: _uuid.v4(),
        documentId: _currentDocumentId!,
        pageNumber: _currentPage,
        label: label,
        createdAt: DateTime.now(),
      );
      await db.insertBookmark(bookmark);
      setState(() {
        _bookmarks.add(bookmark);
        _bookmarks.sort((a, b) => a.pageNumber.compareTo(b.pageNumber));
      });
    }
  }

  Future<String?> _showBookmarkDialog() async {
    final controller = TextEditingController();
    return showDialog<String>(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: const Text('Add Bookmark'),
          content: TextField(
            controller: controller,
            decoration: const InputDecoration(
              hintText: 'Label (optional)',
              labelText: 'Bookmark label',
            ),
            autofocus: true,
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text('Cancel'),
            ),
            TextButton(
              onPressed: () => Navigator.of(context).pop(controller.text),
              child: const Text('Add'),
            ),
          ],
        );
      },
    );
  }

  Future<void> _deleteBookmark(Bookmark bookmark) async {
    final db = await DatabaseService.getInstance();
    await db.deleteBookmark(bookmark.id);
    setState(() {
      _bookmarks.removeWhere((b) => b.id == bookmark.id);
    });
  }

  void _jumpToPage(int page) {
    _saveCurrentPageAnnotations();
    _viewerController.jumpToPage(page + 1);
  }

  // -- Zoom --

  void _zoomIn() {
    final newLevel = (_zoomLevel + 0.25).clamp(0.5, 5.0);
    _viewerController.zoomLevel = newLevel;
    setState(() => _zoomLevel = newLevel);
  }

  void _zoomOut() {
    final newLevel = (_zoomLevel - 0.25).clamp(0.5, 5.0);
    _viewerController.zoomLevel = newLevel;
    setState(() => _zoomLevel = newLevel);
  }

  void _zoomFitWidth() {
    _viewerController.zoomLevel = 1.0;
    setState(() => _zoomLevel = 1.0);
  }

  // -- Search --

  void _openSearch() {
    showDialog(
      context: context,
      builder: (_) => PdfTextSearchDialog(viewerController: _viewerController),
    );
  }

  // -- Export --

  Future<void> _exportPdf() async {
    try {
      final outputPath = await _pdfService.exportAnnotatedPdf(
        widget.filePath,
        _annotations,
      );
      if (mounted) {
        ScaffoldMessenger.of(
          context,
        ).showSnackBar(SnackBar(content: Text('Exported to: $outputPath')));
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(
          context,
        ).showSnackBar(SnackBar(content: Text('Export failed: $e')));
      }
    }
  }

  // -- Page Management --

  void _showPageManagementSheet() {
    showModalBottomSheet(
      context: context,
      builder: (context) {
        final canDelete = _pageCount > 1;
        return SafeArea(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ListTile(
                leading: const Icon(Icons.rotate_right),
                title: const Text('Rotate Page 90\u00B0'),
                subtitle: Text('Page ${_currentPage + 1}'),
                onTap: () {
                  Navigator.of(context).pop();
                  _rotateCurrentPage();
                },
              ),
              ListTile(
                leading: Icon(
                  Icons.delete_outline,
                  color: canDelete ? null : Colors.grey,
                ),
                title: Text(
                  'Delete Page',
                  style: TextStyle(color: canDelete ? null : Colors.grey),
                ),
                subtitle: Text(
                  canDelete
                      ? 'Page ${_currentPage + 1}'
                      : 'Cannot delete the only page',
                ),
                enabled: canDelete,
                onTap: canDelete
                    ? () {
                        Navigator.of(context).pop();
                        _deleteCurrentPage();
                      }
                    : null,
              ),
              ListTile(
                leading: const Icon(Icons.note_add_outlined),
                title: const Text('Insert Blank Page After Current'),
                subtitle: Text('After page ${_currentPage + 1}'),
                onTap: () {
                  Navigator.of(context).pop();
                  _insertBlankPageAfterCurrent();
                },
              ),
            ],
          ),
        );
      },
    );
  }

  /// Transform a stroke's normalized [0,1] points to match a 90° clockwise
  /// page rotation: a point at (x, y) maps to (1 - y, x). Used to keep
  /// existing annotations glued to the page content after the page itself is
  /// physically rotated (PDF /Rotate).
  InkStroke _rotateStroke90CW(InkStroke stroke) {
    return stroke.copyWith(
      points: stroke.points
          .map((p) => p.copyWith(x: 1.0 - p.y, y: p.x))
          .toList(),
    );
  }

  Future<void> _rotateCurrentPage() async {
    final rotatedPage = _currentPage;
    final success = await _pdfService.rotatePage(widget.filePath, rotatedPage);
    if (!success || !mounted) return;
    // Invalidate thumbnail for the rotated page.
    if (_currentDocumentId != null) {
      await ThumbnailService.invalidatePage(_currentDocumentId!, rotatedPage);
    }
    setState(() {
      _pdfMutationVersion++;
      // The page is physically rotated 90° CW, so transform existing stored
      // annotations the same way to keep them aligned with the page content.
      // New strokes drawn afterwards are already captured in the rotated frame.
      final existing = _annotations[rotatedPage];
      if (existing != null && existing.isNotEmpty) {
        _annotations[rotatedPage] = existing.map(_rotateStroke90CW).toList();
        // Undo history holds pre-rotation coordinates; reset it for this page
        // so undo/redo cannot reintroduce misaligned strokes.
        _undoManagers.remove(rotatedPage);
      }
    });
    // Persist the transformed annotations for the rotated page.
    _saveCurrentPageAnnotations(page: rotatedPage);
    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Rotated page ${_currentPage + 1}')),
      );
    }
  }

  Future<void> _deleteCurrentPage() async {
    // Confirm.
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Delete Page'),
        content: Text(
          'Delete page ${_currentPage + 1}? This cannot be undone.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: const Text('Delete', style: TextStyle(color: Colors.red)),
          ),
        ],
      ),
    );
    if (confirmed != true) return;

    final success = await _pdfService.deletePage(widget.filePath, _currentPage);
    if (!success || !mounted) return;

    if (_currentDocumentId != null) {
      final db = await DatabaseService.getInstance();
      // Delete annotation/bookmark/ocr data for the removed page.
      await db.deletePageData(_currentDocumentId!, _currentPage);
      // Remap higher-indexed data down by 1.
      await db.remapAnnotationsAfterDelete(_currentDocumentId!, _currentPage);
      await db.remapBookmarksAfterDelete(_currentDocumentId!, _currentPage);
      // Update stored page count.
      final newCount = _pageCount - 1;
      await db.updateDocumentPageCount(_currentDocumentId!, newCount);
      // Invalidate all thumbnails (page indices shifted).
      await ThumbnailService.invalidateAll(_currentDocumentId!);
    }

    // Shift in-memory annotations down.
    final newAnnotations = <int, List<InkStroke>>{};
    for (final entry in _annotations.entries) {
      if (entry.key < _currentPage) {
        newAnnotations[entry.key] = entry.value;
      } else if (entry.key > _currentPage) {
        newAnnotations[entry.key - 1] = entry.value;
      }
      // entry.key == _currentPage is dropped.
    }
    _annotations
      ..clear()
      ..addAll(newAnnotations);

    // Shift undo managers.
    final newUndoManagers = <int, UndoManager>{};
    for (final entry in _undoManagers.entries) {
      if (entry.key < _currentPage) {
        newUndoManagers[entry.key] = entry.value;
      } else if (entry.key > _currentPage) {
        newUndoManagers[entry.key - 1] = entry.value;
      }
    }
    _undoManagers
      ..clear()
      ..addAll(newUndoManagers);

    // Shift bookmarks in memory.
    _bookmarks.removeWhere((b) => b.pageNumber == _currentPage);
    for (int i = 0; i < _bookmarks.length; i++) {
      if (_bookmarks[i].pageNumber > _currentPage) {
        _bookmarks[i] = Bookmark(
          id: _bookmarks[i].id,
          documentId: _bookmarks[i].documentId,
          pageNumber: _bookmarks[i].pageNumber - 1,
          label: _bookmarks[i].label,
          color: _bookmarks[i].color,
          createdAt: _bookmarks[i].createdAt,
        );
      }
    }

    setState(() {
      _pageCount = _pageCount - 1;
      if (_currentPage >= _pageCount) {
        _currentPage = _pageCount - 1;
      }
      _pdfMutationVersion++;
    });

    if (mounted) {
      ScaffoldMessenger.of(
        context,
      ).showSnackBar(const SnackBar(content: Text('Page deleted')));
    }
  }

  Future<void> _insertBlankPageAfterCurrent() async {
    final success = await _pdfService.insertBlankPage(
      widget.filePath,
      _currentPage,
    );
    if (!success || !mounted) return;

    final insertedIndex = _currentPage + 1;
    if (_currentDocumentId != null) {
      final db = await DatabaseService.getInstance();
      await db.remapAnnotationsAfterInsert(_currentDocumentId!, insertedIndex);
      await db.remapBookmarksAfterInsert(_currentDocumentId!, insertedIndex);
      final newCount = _pageCount + 1;
      await db.updateDocumentPageCount(_currentDocumentId!, newCount);
      await ThumbnailService.invalidateAll(_currentDocumentId!);
    }

    // Shift in-memory annotations up by 1 for pages >= insertedIndex.
    final newAnnotations = <int, List<InkStroke>>{};
    for (final entry in _annotations.entries) {
      if (entry.key < insertedIndex) {
        newAnnotations[entry.key] = entry.value;
      } else {
        newAnnotations[entry.key + 1] = entry.value;
      }
    }
    _annotations
      ..clear()
      ..addAll(newAnnotations);

    final newUndoManagers = <int, UndoManager>{};
    for (final entry in _undoManagers.entries) {
      if (entry.key < insertedIndex) {
        newUndoManagers[entry.key] = entry.value;
      } else {
        newUndoManagers[entry.key + 1] = entry.value;
      }
    }
    _undoManagers
      ..clear()
      ..addAll(newUndoManagers);

    // Shift bookmarks in memory.
    for (int i = 0; i < _bookmarks.length; i++) {
      if (_bookmarks[i].pageNumber >= insertedIndex) {
        _bookmarks[i] = Bookmark(
          id: _bookmarks[i].id,
          documentId: _bookmarks[i].documentId,
          pageNumber: _bookmarks[i].pageNumber + 1,
          label: _bookmarks[i].label,
          color: _bookmarks[i].color,
          createdAt: _bookmarks[i].createdAt,
        );
      }
    }

    setState(() {
      _pageCount = _pageCount + 1;
      _pdfMutationVersion++;
    });

    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Blank page inserted after page ${_currentPage + 1}'),
        ),
      );
    }
  }

  // -- Camera Insert --

  Future<void> _showCameraInsertDialog() async {
    final source = await showDialog<String>(
      context: context,
      builder: (context) => SimpleDialog(
        title: const Text('Insert Image'),
        children: [
          SimpleDialogOption(
            onPressed: () => Navigator.of(context).pop('camera'),
            child: const ListTile(
              leading: Icon(Icons.camera_alt),
              title: Text('Camera'),
            ),
          ),
          SimpleDialogOption(
            onPressed: () => Navigator.of(context).pop('gallery'),
            child: const ListTile(
              leading: Icon(Icons.photo_library),
              title: Text('Gallery'),
            ),
          ),
        ],
      ),
    );
    if (source == null || !mounted) return;

    final String? imagePath;
    if (source == 'camera') {
      imagePath = await _cameraService.capturePhoto();
    } else {
      imagePath = await _cameraService.pickFromGallery();
    }
    if (imagePath == null || !mounted) return;

    final result = await _pdfService.insertImageOnPage(
      widget.filePath,
      _currentPage,
      imagePath,
    );
    if (result != null && mounted) {
      if (_currentDocumentId != null) {
        await ThumbnailService.invalidatePage(
          _currentDocumentId!,
          _currentPage,
        );
      }
      setState(() {
        _pdfMutationVersion++;
      });
      // Save current annotations so they overlay the image.
      _saveCurrentPageAnnotations();
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Image inserted on page ${_currentPage + 1}')),
        );
      }
    } else if (mounted) {
      ScaffoldMessenger.of(
        context,
      ).showSnackBar(const SnackBar(content: Text('Failed to insert image')));
    }
  }

  // -- Bookmark drawer --

  Widget _buildBookmarkDrawer() {
    return Drawer(
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16),
            child: Text(
              'Bookmarks',
              style: Theme.of(context).textTheme.headlineSmall,
            ),
          ),
          Expanded(
            child: _bookmarks.isEmpty
                ? Center(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Icon(
                          Icons.bookmark_border,
                          size: 48,
                          color: Theme.of(context).colorScheme.onSurfaceVariant,
                        ),
                        const SizedBox(height: 12),
                        const Text(
                          'No bookmarks yet',
                          style: TextStyle(fontWeight: FontWeight.w600),
                        ),
                        const SizedBox(height: 4),
                        const Text(
                          'Tap the bookmark icon in the toolbar\nto bookmark the current page.',
                          textAlign: TextAlign.center,
                        ),
                      ],
                    ),
                  )
                : ListView.builder(
                    itemCount: _bookmarks.length,
                    itemBuilder: (context, index) {
                      final bookmark = _bookmarks[index];
                      return ListTile(
                        leading: CircleAvatar(
                          backgroundColor: Color(bookmark.color),
                          radius: 6,
                        ),
                        title: Text(
                          bookmark.label.isEmpty
                              ? 'Page ${bookmark.pageNumber + 1}'
                              : bookmark.label,
                        ),
                        subtitle: Text('Page ${bookmark.pageNumber + 1}'),
                        trailing: IconButton(
                          icon: const Icon(Icons.delete_outline),
                          tooltip: 'Delete bookmark',
                          onPressed: () => _deleteBookmark(bookmark),
                        ),
                        onTap: () {
                          Navigator.of(context).pop();
                          _jumpToPage(bookmark.pageNumber);
                        },
                        onLongPress: () => _deleteBookmark(bookmark),
                      );
                    },
                  ),
          ),
        ],
      ),
    );
  }

  // -- UI --

  @override
  Widget build(BuildContext context) {
    final undoManager = _getUndoManager(_currentPage);
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: Text(_fileName, style: const TextStyle(fontSize: 16)),
        actions: [
          IconButton(
            icon: const Icon(Icons.vertical_split),
            tooltip: 'Open in Split View',
            onPressed: () {
              if (_currentDocumentId == null) return;
              _saveCurrentPageAnnotations();
              Navigator.of(context).push(
                MaterialPageRoute(
                  builder: (_) => SplitViewScreen(
                    filePath: widget.filePath,
                    documentId: _currentDocumentId!,
                  ),
                ),
              );
            },
          ),
          IconButton(
            icon: const Icon(Icons.search),
            tooltip: 'Search in PDF (Ctrl+F)',
            onPressed: _openSearch,
          ),
          IconButton(
            icon: Icon(
              _isCurrentPageBookmarked ? Icons.bookmark : Icons.bookmark_border,
            ),
            tooltip: 'Toggle bookmark',
            onPressed: _toggleBookmark,
          ),
          IconButton(
            icon: const Icon(Icons.menu_book),
            tooltip: 'Bookmarks',
            onPressed: () => _scaffoldKey.currentState?.openEndDrawer(),
          ),
          IconButton(
            icon: Icon(
              _showThumbnails
                  ? Icons.view_sidebar
                  : Icons.view_sidebar_outlined,
            ),
            tooltip: 'Toggle page thumbnails',
            onPressed: () => setState(() => _showThumbnails = !_showThumbnails),
          ),
          PopupMenuButton<_OverflowAction>(
            icon: const Icon(Icons.more_vert),
            tooltip: 'More actions',
            onSelected: (action) {
              switch (action) {
                case _OverflowAction.pageManagement:
                  _showPageManagementSheet();
                case _OverflowAction.cameraInsert:
                  _showCameraInsertDialog();
                case _OverflowAction.export:
                  _exportPdf();
              }
            },
            itemBuilder: (context) => const [
              PopupMenuItem(
                value: _OverflowAction.pageManagement,
                child: ListTile(
                  leading: Icon(Icons.pages),
                  title: Text('Page Management'),
                  contentPadding: EdgeInsets.zero,
                ),
              ),
              PopupMenuItem(
                value: _OverflowAction.cameraInsert,
                child: ListTile(
                  leading: Icon(Icons.camera_alt),
                  title: Text('Insert Image'),
                  contentPadding: EdgeInsets.zero,
                ),
              ),
              PopupMenuItem(
                value: _OverflowAction.export,
                child: ListTile(
                  leading: Icon(Icons.save_alt),
                  title: Text('Export PDF'),
                  contentPadding: EdgeInsets.zero,
                ),
              ),
            ],
          ),
        ],
      ),
      endDrawer: _buildBookmarkDrawer(),
      body: CallbackShortcuts(
        bindings: {
          const SingleActivator(LogicalKeyboardKey.keyZ, control: true): _undo,
          const SingleActivator(LogicalKeyboardKey.keyY, control: true): _redo,
          const SingleActivator(
            LogicalKeyboardKey.keyZ,
            control: true,
            shift: true,
          ): _redo,
          const SingleActivator(LogicalKeyboardKey.keyF, control: true):
              _openSearch,
          const SingleActivator(LogicalKeyboardKey.keyS, control: true):
              _saveCurrentPageAnnotations,
          const SingleActivator(LogicalKeyboardKey.escape): () {
            if (_interactionMode != InteractionMode.navigate) {
              setState(() => _interactionMode = InteractionMode.navigate);
            }
          },
        },
        child: Focus(
          autofocus: true,
          child: Column(
            children: [
              AnnotationToolbar(
                currentTool: _currentTool,
                currentColor: _currentColor,
                currentStrokeWidth: _currentStrokeWidth,
                filled: _filled,
                pressureCurveType: _pressureCurveType,
                stabilizationLevel: _stabilizationLevel,
                canUndo: undoManager.canUndo,
                canRedo: undoManager.canRedo,
                onToolChanged: (tool) => setState(() => _currentTool = tool),
                onColorChanged: (color) =>
                    setState(() => _currentColor = color),
                onStrokeWidthChanged: (w) =>
                    setState(() => _currentStrokeWidth = w),
                onFilledChanged: (f) => setState(() => _filled = f),
                onPressureCurveChanged: (v) =>
                    setState(() => _pressureCurveType = v),
                onStabilizationChanged: (v) =>
                    setState(() => _stabilizationLevel = v),
                onUndo: _undo,
                onRedo: _redo,
                onPreviousPage: _currentPage > 0
                    ? () => _viewerController.previousPage()
                    : null,
                onNextPage: _currentPage < _pageCount - 1
                    ? () => _viewerController.nextPage()
                    : null,
                pageInfo: '${_currentPage + 1} / $_pageCount',
                interactionMode: _interactionMode,
                onInteractionModeChanged: (mode) =>
                    setState(() => _interactionMode = mode),
                onZoomIn: _zoomIn,
                onZoomOut: _zoomOut,
                onZoomFitWidth: _zoomFitWidth,
                zoomLabel: '${(_zoomLevel * 100).round()}%',
              ),
              Expanded(
                child: Row(
                  children: [
                    if (_showThumbnails && _currentDocumentId != null)
                      PageThumbnailSidebar(
                        documentId: _currentDocumentId!,
                        filePath: widget.filePath,
                        pageCount: _pageCount,
                        currentPage: _currentPage,
                        onPageTap: _jumpToPage,
                        bookmarkedPages: _bookmarks
                            .map((b) => b.pageNumber)
                            .toSet(),
                      ),
                    Expanded(
                      child: Stack(
                        children: [
                          SfPdfViewer.file(
                            File(widget.filePath),
                            key: ValueKey('pdf-$_pdfMutationVersion'),
                            controller: _viewerController,
                            initialPageNumber: _currentPage + 1,
                            onPageChanged: (PdfPageChangedDetails details) {
                              _onPageChanged(details.newPageNumber - 1);
                            },
                          ),
                          Positioned.fill(
                            child: _interactionMode == InteractionMode.navigate
                                ? IgnorePointer(
                                    child: PdfAnnotationLayer(
                                      strokes: _getCurrentStrokes(),
                                      onStrokeComplete: _onStrokeComplete,
                                      onErase: _onErase,
                                      tool: _currentTool,
                                      color: _currentColor,
                                      strokeWidth: _currentStrokeWidth,
                                      filled: _filled,
                                      interactionMode: _interactionMode,
                                    ),
                                  )
                                : PdfAnnotationLayer(
                                    strokes: _getCurrentStrokes(),
                                    onStrokeComplete: _onStrokeComplete,
                                    onErase: _onErase,
                                    tool: _currentTool,
                                    color: _currentColor,
                                    strokeWidth: _currentStrokeWidth,
                                    filled: _filled,
                                    interactionMode: _interactionMode,
                                  ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _saveCurrentPageAnnotations();
    _viewerController.dispose();
    super.dispose();
  }
}
