import 'package:flutter/material.dart';

import '../models/ink_point.dart';
import '../models/ink_stroke.dart';
import '../models/pen_tool.dart';
import '../widgets/ink_canvas.dart';

/// Transparent overlay widget positioned on top of the PDF viewer.
///
/// Reuses the existing [InkCanvas] widget for ink rendering.
/// Coordinates are normalized to [0, 1] relative to the overlay size,
/// enabling correct mapping to PDF page coordinates during export.
class PdfAnnotationLayer extends StatefulWidget {
  final List<InkStroke> strokes;
  final void Function(InkStroke stroke)? onStrokeComplete;
  final void Function(String strokeId, List<InkStroke> replacements)? onErase;
  final PenTool tool;
  final Color color;
  final double strokeWidth;
  final bool filled;
  final InteractionMode interactionMode;
  final int rotation;

  const PdfAnnotationLayer({
    super.key,
    required this.strokes,
    this.onStrokeComplete,
    this.onErase,
    this.tool = PenTool.pen,
    this.color = Colors.black,
    this.strokeWidth = 2.0,
    this.filled = false,
    this.interactionMode = InteractionMode.draw,
    this.rotation = 0,
  });

  @override
  State<PdfAnnotationLayer> createState() => _PdfAnnotationLayerState();
}

class _PdfAnnotationLayerState extends State<PdfAnnotationLayer> {
  Size _canvasSize = Size.zero;

  /// Applies inverse rotation to normalized coordinates for rendering.
  /// Converts from stored (possibly rotated) coords back to display coords.
  Offset _inverseRotate(double nx, double ny, int rotation) {
    switch (rotation % 360) {
      case 90:
        return Offset(1.0 - ny, nx);
      case 180:
        return Offset(1.0 - nx, 1.0 - ny);
      case 270:
        return Offset(ny, 1.0 - nx);
      default:
        return Offset(nx, ny);
    }
  }

  /// Applies forward rotation to normalized coordinates before storage.
  /// Converts from display coords to the canonical rotated representation.
  Offset _forwardRotate(double nx, double ny, int rotation) {
    switch (rotation % 360) {
      case 90:
        return Offset(ny, 1.0 - nx);
      case 180:
        return Offset(1.0 - nx, 1.0 - ny);
      case 270:
        return Offset(1.0 - ny, nx);
      default:
        return Offset(nx, ny);
    }
  }

  /// Scales a stroke's points from normalized [0, 1] coordinates to
  /// the current canvas pixel coordinates for rendering.
  /// Applies inverse rotation before scaling so strokes render correctly
  /// on a rotated page.
  List<InkStroke> get _scaledStrokes {
    if (_canvasSize == Size.zero) return widget.strokes;
    return widget.strokes.map((stroke) {
      return InkStroke(
        id: stroke.id,
        points: stroke.points.map((pt) {
          final rotated = _inverseRotate(pt.x, pt.y, widget.rotation);
          return InkPoint(
            x: rotated.dx * _canvasSize.width,
            y: rotated.dy * _canvasSize.height,
            pressure: pt.pressure,
            tilt: pt.tilt,
            timestamp: pt.timestamp,
            pointerDeviceKind: pt.pointerDeviceKind,
          );
        }).toList(),
        tool: stroke.tool,
        color: stroke.color,
        strokeWidth: stroke.strokeWidth,
        createdAt: stroke.createdAt,
        filled: stroke.filled,
        textContent: stroke.textContent,
        fontSize: stroke.fontSize,
      );
    }).toList();
  }

  /// Normalizes a stroke's points from canvas pixel coordinates to
  /// [0, 1] relative to the overlay size.
  /// Applies forward rotation before storage so the canonical representation
  /// accounts for the current page rotation.
  InkStroke _normalizeStroke(InkStroke stroke) {
    if (_canvasSize == Size.zero) return stroke;
    return InkStroke(
      id: stroke.id,
      points: stroke.points.map((pt) {
        final nx = pt.x / _canvasSize.width;
        final ny = pt.y / _canvasSize.height;
        final rotated = _forwardRotate(nx, ny, widget.rotation);
        return InkPoint(
          x: rotated.dx,
          y: rotated.dy,
          pressure: pt.pressure,
          tilt: pt.tilt,
          timestamp: pt.timestamp,
          pointerDeviceKind: pt.pointerDeviceKind,
        );
      }).toList(),
      tool: stroke.tool,
      color: stroke.color,
      strokeWidth: stroke.strokeWidth,
      createdAt: stroke.createdAt,
      filled: stroke.filled,
      textContent: stroke.textContent,
      fontSize: stroke.fontSize,
    );
  }

  void _onStrokeComplete(InkStroke stroke) {
    widget.onStrokeComplete?.call(_normalizeStroke(stroke));
  }

  void _onErase(String strokeId, List<InkStroke> replacements) {
    widget.onErase?.call(strokeId, replacements.map(_normalizeStroke).toList());
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        _canvasSize = Size(constraints.maxWidth, constraints.maxHeight);
        return InkCanvas(
          strokes: _scaledStrokes,
          onStrokeComplete: _onStrokeComplete,
          onErase: _onErase,
          tool: widget.tool,
          color: widget.color,
          strokeWidth: widget.strokeWidth,
          filled: widget.filled,
          interactionMode: widget.interactionMode,
        );
      },
    );
  }
}
