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

import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';

import '../models/ink_stroke.dart';
import '../models/pen_tool.dart';
import '../models/pressure_curve.dart';
import '../services/database_service.dart';
import '../services/undo_manager.dart';
import '../utils/stroke_stabilizer.dart';
import '../widgets/annotation_toolbar.dart';
import '../widgets/ink_canvas.dart';

/// Split-view derivation mode: left pane = reference PDF, right pane = infinite
/// scratchpad for formula derivation. Scratchpad strokes are persisted per
/// document via [DatabaseService.saveScratchpad] / [DatabaseService.loadScratchpad].
class SplitViewScreen extends StatefulWidget {
  final String filePath;
  final String documentId;

  const SplitViewScreen({
    super.key,
    required this.filePath,
    required this.documentId,
  });

  @override
  State<SplitViewScreen> createState() => _SplitViewState();
}

class _SplitViewState extends State<SplitViewScreen> {
  // -- PDF (left pane) --
  final PdfViewerController _pdfController = PdfViewerController();
  int _currentPage = 0;
  int _pageCount = 0;
  String _fileName = '';

  // -- Split divider --
  double _leftPaneFraction = 0.5;
  bool _isDraggingDivider = false;

  // -- Scratchpad (right pane) --
  final UndoManager _undoManager = UndoManager();
  List<InkStroke> _strokes = [];
  double _canvasWidth = 4000;
  double _canvasHeight = 4000;

  // -- Tool state --
  PenTool _currentTool = PenTool.pen;
  Color _currentColor = Colors.black;
  double _currentStrokeWidth = 2.0;
  bool _filled = false;
  PressureCurveType _pressureCurveType = PressureCurveType.linear;
  StabilizationLevel _stabilizationLevel = StabilizationLevel.none;

  // -- Auto-save debounce --
  Timer? _saveTimer;
  bool _dirty = false;

  // -- Page link markers (optional feature) --
  final List<_PageLink> _pageLinks = [];

  static const double _edgeThreshold = 200.0;
  static const double _expandAmount = 1000.0;

  @override
  void initState() {
    super.initState();
    _loadScratchpad();
  }

  @override
  void dispose() {
    _saveTimer?.cancel();
    _saveImmediate();
    _pdfController.dispose();
    super.dispose();
  }

  // -- Persistence --

  Future<void> _loadScratchpad() async {
    final db = await DatabaseService.getInstance();
    final strokes = await db.loadScratchpad(widget.documentId);
    if (mounted) {
      setState(() {
        _strokes = strokes;
        for (final s in strokes) {
          _undoManager.addStroke(s);
        }
      });
    }
  }

  void _scheduleSave() {
    _dirty = true;
    _saveTimer?.cancel();
    _saveTimer = Timer(const Duration(seconds: 3), _saveImmediate);
  }

  Future<void> _saveImmediate() async {
    if (!_dirty) return;
    _dirty = false;
    final db = await DatabaseService.getInstance();
    final json = jsonEncode(_strokes.map((s) => s.toJson()).toList());
    await db.saveScratchpad(widget.documentId, json);
  }

  // -- Scratchpad stroke callbacks --

  void _onStrokeComplete(InkStroke stroke) {
    setState(() {
      _strokes.add(stroke);
      _undoManager.addStroke(stroke);
      _checkCanvasExpansion(stroke);
    });
    _scheduleSave();
  }

  void _onErase(String strokeId, List<InkStroke> replacements) {
    setState(() {
      final original = _strokes.where((s) => s.id == strokeId).firstOrNull;
      if (original != null) {
        _undoManager.removeStroke(original, replacements: replacements);
        _strokes = List.from(_undoManager.currentStrokes);
      }
    });
    _scheduleSave();
  }

  void _undo() {
    setState(() {
      _undoManager.undo();
      _strokes = List.from(_undoManager.currentStrokes);
    });
    _scheduleSave();
  }

  void _redo() {
    setState(() {
      _undoManager.redo();
      _strokes = List.from(_undoManager.currentStrokes);
    });
    _scheduleSave();
  }

  // -- Auto-expand canvas --

  void _checkCanvasExpansion(InkStroke stroke) {
    double maxRight = 0;
    double maxBottom = 0;
    for (final p in stroke.points) {
      if (p.x > maxRight) maxRight = p.x;
      if (p.y > maxBottom) maxBottom = p.y;
    }
    bool expanded = false;
    if (maxRight > _canvasWidth - _edgeThreshold) {
      _canvasWidth += _expandAmount;
      expanded = true;
    }
    if (maxBottom > _canvasHeight - _edgeThreshold) {
      _canvasHeight += _expandAmount;
      expanded = true;
    }
    if (expanded) setState(() {});
  }

  // -- Divider drag --

  void _onDividerDragStart(DragStartDetails details) {
    setState(() => _isDraggingDivider = true);
  }

  void _onDividerDragUpdate(
    DragUpdateDetails details,
    BoxConstraints constraints,
  ) {
    final renderWidth = constraints.maxWidth;
    if (renderWidth <= 0) return;
    final delta = details.delta.dx / renderWidth;
    setState(() {
      _leftPaneFraction = (_leftPaneFraction + delta).clamp(0.2, 0.8);
    });
  }

  void _onDividerDragEnd(DragEndDetails details) {
    setState(() => _isDraggingDivider = false);
  }

  // -- PDF page navigation --

  void _prevPage() {
    if (_currentPage > 0) {
      _pdfController.previousPage();
    }
  }

  void _nextPage() {
    if (_currentPage < _pageCount - 1) {
      _pdfController.nextPage();
    }
  }

  // -- Page link creation (long-press on left pane) --

  void _onPdfLongPress(int pageNumber) {
    // Place a page link marker at the current scratchpad viewport center.
    // We approximate the viewport center as (0, 0) since InteractiveViewer
    // manages its own transform — the user can reposition by panning.
    setState(() {
      _pageLinks.add(
        _PageLink(
          pageNumber: pageNumber,
          position: const Offset(100, 100), // default top-left area
        ),
      );
    });
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Page link marker added for page $pageNumber')),
    );
  }

  void _onPageLinkTap(_PageLink link) {
    _pdfController.jumpToPage(link.pageNumber);
    setState(() {
      _currentPage = link.pageNumber - 1;
    });
  }

  void _deletePageLink(_PageLink link) {
    setState(() {
      _pageLinks.remove(link);
    });
  }

  // -- Build --

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          _fileName.isEmpty ? 'Split View' : _fileName,
          style: const TextStyle(fontSize: 16),
        ),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () {
            _saveImmediate();
            Navigator.of(context).pop();
          },
        ),
        actions: [
          // Left pane page navigation
          IconButton(
            icon: const Icon(Icons.navigate_before),
            tooltip: 'Previous page (PDF)',
            onPressed: _currentPage > 0 ? _prevPage : null,
          ),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 4),
            child: Center(
              child: Text(
                '${_currentPage + 1} / $_pageCount',
                style: const TextStyle(fontSize: 13),
              ),
            ),
          ),
          IconButton(
            icon: const Icon(Icons.navigate_next),
            tooltip: 'Next page (PDF)',
            onPressed: _currentPage < _pageCount - 1 ? _nextPage : null,
          ),
          const SizedBox(width: 8),
          // Canvas info
          Tooltip(
            message:
                'Scratchpad size: ${_canvasWidth.round()} x ${_canvasHeight.round()}',
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 8),
              child: Center(
                child: Text(
                  '${_canvasWidth.round()}x${_canvasHeight.round()}',
                  style: const TextStyle(fontSize: 11, color: Colors.grey),
                ),
              ),
            ),
          ),
        ],
      ),
      body: Column(
        children: [
          // Label clarifying that the toolbar controls the scratchpad pane.
          Padding(
            padding: const EdgeInsets.only(left: 12, top: 4),
            child: Align(
              alignment: Alignment.centerLeft,
              child: Text(
                'Scratchpad tools',
                style: Theme.of(context).textTheme.labelSmall?.copyWith(
                  color: Theme.of(context).colorScheme.onSurfaceVariant,
                ),
              ),
            ),
          ),
          // Toolbar (applies to scratchpad only)
          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,
          ),
          // Split view body
          Expanded(
            child: LayoutBuilder(
              builder: (context, constraints) {
                final totalWidth = constraints.maxWidth;
                final leftWidth = totalWidth * _leftPaneFraction;
                final rightWidth =
                    totalWidth - leftWidth - 12; // 12px divider hit area

                return Row(
                  children: [
                    // Left pane: PDF reference (read-only)
                    SizedBox(width: leftWidth, child: _buildPdfPane()),
                    // Draggable divider: 12px hit area, 4px visual strip.
                    GestureDetector(
                      onHorizontalDragStart: _onDividerDragStart,
                      onHorizontalDragUpdate: (d) =>
                          _onDividerDragUpdate(d, constraints),
                      onHorizontalDragEnd: _onDividerDragEnd,
                      child: MouseRegion(
                        cursor: SystemMouseCursors.resizeColumn,
                        child: SizedBox(
                          width: 12,
                          child: Center(
                            child: Container(
                              width: 4,
                              color: _isDraggingDivider
                                  ? Theme.of(context).colorScheme.primary
                                  : Theme.of(context).dividerColor,
                            ),
                          ),
                        ),
                      ),
                    ),
                    // Right pane: Infinite scratchpad
                    SizedBox(width: rightWidth, child: _buildScratchpadPane()),
                  ],
                );
              },
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildPdfPane() {
    return Stack(
      children: [
        GestureDetector(
          onLongPress: () {
            // Long-press on PDF to create page link marker
            _onPdfLongPress(_currentPage + 1);
          },
          child: SfPdfViewer.file(
            File(widget.filePath),
            controller: _pdfController,
            canShowScrollHead: true,
            canShowScrollStatus: true,
            onPageChanged: (PdfPageChangedDetails details) {
              setState(() {
                _currentPage = details.newPageNumber - 1;
              });
            },
            onDocumentLoaded: (PdfDocumentLoadedDetails details) {
              setState(() {
                _pageCount = details.document.pages.count;
                _fileName = widget.filePath.split(Platform.pathSeparator).last;
              });
            },
          ),
        ),
        // Page link markers overlay (on PDF pane, showing linked pages)
        if (_pageLinks.isNotEmpty)
          Positioned(bottom: 8, left: 8, child: _buildPageLinkChips()),
      ],
    );
  }

  Widget _buildPageLinkChips() {
    return Wrap(
      spacing: 4,
      runSpacing: 4,
      children: _pageLinks.map((link) {
        return GestureDetector(
          onTap: () => _onPageLinkTap(link),
          onLongPress: () => _deletePageLink(link),
          child: Chip(
            avatar: const Icon(Icons.link, size: 14, color: Colors.white),
            label: Text(
              'p${link.pageNumber}',
              style: const TextStyle(fontSize: 11, color: Colors.white),
            ),
            backgroundColor: Colors.blue.shade600,
            padding: EdgeInsets.zero,
            materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
            visualDensity: VisualDensity.compact,
          ),
        );
      }).toList(),
    );
  }

  Widget _buildScratchpadPane() {
    return Container(
      color: Theme.of(context).scaffoldBackgroundColor,
      child: InteractiveViewer(
        constrained: false,
        minScale: 0.25,
        maxScale: 8.0,
        boundaryMargin: const EdgeInsets.all(double.infinity),
        child: SizedBox(
          width: _canvasWidth,
          height: _canvasHeight,
          child: InkCanvas(
            strokes: _strokes,
            onStrokeComplete: _onStrokeComplete,
            onErase: _onErase,
            tool: _currentTool,
            color: _currentColor,
            strokeWidth: _currentStrokeWidth,
            pressureCurve: PressureCurve(type: _pressureCurveType),
            stabilizationLevel: _stabilizationLevel,
            filled: _filled,
            interactionMode: InteractionMode.draw,
          ),
        ),
      ),
    );
  }
}

/// A marker linking a scratchpad position to a specific PDF page.
class _PageLink {
  final int pageNumber;
  final Offset position;

  const _PageLink({required this.pageNumber, required this.position});
}
