import 'package:flutter/material.dart';
import 'package:flutter/services.dart' hide UndoManager;
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../models/ink_stroke.dart';
import '../models/note.dart';
import '../models/pen_tool.dart';
import '../models/pressure_curve.dart';
import '../providers/note_provider.dart';
import '../providers/ocr_provider.dart';
import '../services/undo_manager.dart';
import '../utils/stroke_stabilizer.dart';
import '../widgets/annotation_toolbar.dart';
import '../widgets/ink_canvas.dart';

class NoteEditorScreen extends ConsumerStatefulWidget {
  final Note? note;

  const NoteEditorScreen({super.key, this.note});

  @override
  ConsumerState<NoteEditorScreen> createState() => _NoteEditorScreenState();
}

class _NoteEditorScreenState extends ConsumerState<NoteEditorScreen> {
  final UndoManager _undoManager = UndoManager();
  PenTool _currentTool = PenTool.pen;
  Color _currentColor = Colors.black;
  double _currentStrokeWidth = 2.0;
  bool _filled = false;
  String _title = 'Untitled';
  final TextEditingController _titleController = TextEditingController();
  PressureCurveType _pressureCurveType = PressureCurveType.linear;
  StabilizationLevel _stabilizationLevel = StabilizationLevel.none;
  final TransformationController _zoomController = TransformationController();
  double _zoomLevel = 1.0;

  bool _isDirty = false;

  Note? get _existingNote => widget.note;

  PressureCurve get _pressureCurve {
    switch (_pressureCurveType) {
      case PressureCurveType.linear:
        return PressureCurve.linear;
      case PressureCurveType.soft:
        return PressureCurve.soft;
      case PressureCurveType.hard:
        return PressureCurve.hard;
      case PressureCurveType.custom:
        return const PressureCurve(type: PressureCurveType.custom);
    }
  }

  @override
  void initState() {
    super.initState();
    if (_existingNote != null) {
      _title = _existingNote!.title;
      for (final stroke in _existingNote!.strokes) {
        _undoManager.addStroke(stroke);
      }
    }
    _titleController.text = _title;
  }

  @override
  void dispose() {
    _titleController.dispose();
    _zoomController.dispose();
    super.dispose();
  }

  void _onStrokeComplete(InkStroke stroke) {
    setState(() {
      _undoManager.addStroke(stroke);
      _isDirty = true;
    });
  }

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

  void _undo() {
    setState(() {
      _undoManager.undo();
      _isDirty = true;
    });
  }

  void _redo() {
    setState(() {
      _undoManager.redo();
      _isDirty = true;
    });
  }

  Future<void> _save() async {
    final notifier = ref.read(noteListProvider.notifier);
    final now = DateTime.now();

    Note savedNote;
    if (_existingNote != null) {
      final updated = _existingNote!.copyWith(
        title: _title,
        strokes: _undoManager.currentStrokes.toList(),
        updatedAt: now,
      );
      await notifier.updateNote(updated);
      savedNote = updated;
    } else {
      final note = await notifier.createNote(title: _title);
      final updated = note.copyWith(
        strokes: _undoManager.currentStrokes.toList(),
      );
      await notifier.updateNote(updated);
      savedNote = updated;
    }

    if (!mounted) return;
    setState(() {
      _isDirty = false;
    });

    _runLocalOcr(savedNote);
  }

  /// Run local OCR and index results for search.
  void _runLocalOcr(Note note) {
    final noteId = note.id;
    ref.read(ocrStatusProvider.notifier).state = {
      ...ref.read(ocrStatusProvider),
      noteId: OcrStatus.processing,
    };

    ref
        .read(ocrServiceProvider)
        .processNote(note)
        .then((_) {
          if (!mounted) return;
          ref.read(ocrStatusProvider.notifier).state = {
            ...ref.read(ocrStatusProvider),
            noteId: OcrStatus.done,
          };
        })
        .catchError((_) {
          if (!mounted) return;
          ref.read(ocrStatusProvider.notifier).state = {
            ...ref.read(ocrStatusProvider),
            noteId: OcrStatus.failed,
          };
        });
  }

  void _zoomIn() {
    final newLevel = (_zoomLevel + 0.25).clamp(0.5, 5.0);
    _applyZoom(newLevel);
  }

  void _zoomOut() {
    final newLevel = (_zoomLevel - 0.25).clamp(0.5, 5.0);
    _applyZoom(newLevel);
  }

  void _zoomReset() {
    _applyZoom(1.0);
  }

  void _applyZoom(double level) {
    setState(() => _zoomLevel = level);
    _zoomController.value = Matrix4.diagonal3Values(level, level, 1.0);
  }

  Future<void> _saveAndNotify() async {
    await _save();
    if (!mounted) return;
    ScaffoldMessenger.of(
      context,
    ).showSnackBar(const SnackBar(content: Text('Saved')));
  }

  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: true,
      onPopInvokedWithResult: (didPop, _) {
        if (didPop && _isDirty) _save();
      },
      child: 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,
          SingleActivator(LogicalKeyboardKey.keyS, control: true):
              _saveAndNotify,
        },
        child: Focus(
          autofocus: true,
          child: Scaffold(
            appBar: AppBar(
              title: SizedBox(
                height: 40,
                child: TextField(
                  controller: _titleController,
                  style: const TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.w600,
                  ),
                  decoration: InputDecoration(
                    border: InputBorder.none,
                    hintText: 'Note title...',
                    contentPadding: const EdgeInsets.symmetric(vertical: 8),
                    suffix: _isDirty
                        ? const Text(
                            ' •',
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 18,
                            ),
                          )
                        : null,
                  ),
                  onChanged: (value) {
                    _title = value;
                    setState(() => _isDirty = true);
                  },
                ),
              ),
              actions: [
                IconButton(
                  icon: const Icon(Icons.check),
                  tooltip: 'Save',
                  onPressed: _saveAndNotify,
                ),
              ],
            ),
            body: 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,
                  onZoomIn: _zoomIn,
                  onZoomOut: _zoomOut,
                  onZoomFitWidth: _zoomReset,
                  zoomLabel: '${(_zoomLevel * 100).round()}%',
                ),
                Expanded(
                  child: InteractiveViewer(
                    transformationController: _zoomController,
                    minScale: 0.5,
                    maxScale: 5.0,
                    child: InkCanvas(
                      strokes: _undoManager.currentStrokes,
                      onStrokeComplete: _onStrokeComplete,
                      onErase: _onErase,
                      tool: _currentTool,
                      color: _currentColor,
                      strokeWidth: _currentStrokeWidth,
                      pressureCurve: _pressureCurve,
                      stabilizationLevel: _stabilizationLevel,
                      filled: _filled,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
