/// 自然写互动课堂平板端应用软件 V1.0
/// Skia笔迹渲染器 - CustomPainter实现触屏直写与点阵笔笔迹渲染
///
/// 功能说明：
/// 1. CustomPainter高性能笔迹绘制（Skia引擎）
/// 2. 触屏直写支持（手指/触控笔Pointer事件处理）
/// 3. 点阵笔BLE数据渲染（从BLE服务接收坐标数据）
/// 4. 压力感应笔锋效果（触控笔ActiveStylus压力数据）
/// 5. 贝塞尔曲线平滑算法
/// 6. 字帖练习辅助线（田字格/米字格/四线三格）
/// 7. 撤销/重做操作栈
/// 8. 笔迹导出（SVG/PNG格式）

import 'dart:math';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';

/* ========== 数据模型 ========== */

/// 笔迹点
class PadStrokePoint {
  final double x;
  final double y;
  final double pressure;
  final int timestamp;

  const PadStrokePoint({
    required this.x,
    required this.y,
    this.pressure = 0.5,
    required this.timestamp,
  });

  Map<String, dynamic> toJson() => {
    'x': x, 'y': y, 'pressure': pressure, 'timestamp': timestamp,
  };
}

/// 笔画
class PadStroke {
  final List<PadStrokePoint> points;
  final Color color;
  final double baseWidth;
  final String source; // 'touch'=触屏, 'ble'=点阵笔

  PadStroke({
    List<PadStrokePoint>? points,
    this.color = Colors.black,
    this.baseWidth = 2.5,
    this.source = 'touch',
  }) : points = points ?? [];

  void addPoint(PadStrokePoint point) => points.add(point);
}

/// 辅助线类型
enum GuideLineType {
  none,           // 无辅助线
  tianZiGe,       // 田字格
  miZiGe,         // 米字格
  siXianSanGe,    // 四线三格（英文/拼音）
}

/// 撤销/重做操作
sealed class CanvasAction {}
class AddStrokeAction extends CanvasAction {
  final PadStroke stroke;
  AddStrokeAction(this.stroke);
}
class ClearAction extends CanvasAction {
  final List<PadStroke> clearedStrokes;
  ClearAction(this.clearedStrokes);
}

/* ========== 笔迹画布Widget ========== */

/// 平板端笔迹渲染画布
/// 支持触屏直写和BLE点阵笔两种输入方式
class PadStrokeCanvas extends StatefulWidget {
  /// 初始笔画数据（如加载已有作业笔迹）
  final List<PadStroke>? initialStrokes;

  /// 辅助线类型
  final GuideLineType guideLineType;

  /// 是否只读模式（查看已提交的作业）
  final bool readOnly;

  /// 笔迹颜色
  final Color strokeColor;

  /// 笔画宽度
  final double strokeWidth;

  /// 笔迹变化回调
  final Function(List<PadStroke>)? onStrokesChanged;

  const PadStrokeCanvas({
    super.key,
    this.initialStrokes,
    this.guideLineType = GuideLineType.none,
    this.readOnly = false,
    this.strokeColor = Colors.black,
    this.strokeWidth = 2.5,
    this.onStrokesChanged,
  });

  @override
  State<PadStrokeCanvas> createState() => _PadStrokeCanvasState();
}

class _PadStrokeCanvasState extends State<PadStrokeCanvas> {
  /// 已完成的笔画列表
  final List<PadStroke> _strokes = [];

  /// 当前正在绘制的笔画
  PadStroke? _currentStroke;

  /// 撤销栈
  final List<CanvasAction> _undoStack = [];

  /// 重做栈
  final List<CanvasAction> _redoStack = [];

  /// 最大撤销步数
  static const int maxUndoSteps = 50;

  @override
  void initState() {
    super.initState();
    if (widget.initialStrokes != null) {
      _strokes.addAll(widget.initialStrokes!);
    }
  }

  /// 撤销最后一个操作
  void undo() {
    if (_undoStack.isEmpty) return;
    final action = _undoStack.removeLast();
    if (action is AddStrokeAction) {
      _strokes.remove(action.stroke);
      _redoStack.add(action);
    } else if (action is ClearAction) {
      _strokes.addAll(action.clearedStrokes);
      _redoStack.add(action);
    }
    setState(() {});
    widget.onStrokesChanged?.call(_strokes);
  }

  /// 重做上一个撤销的操作
  void redo() {
    if (_redoStack.isEmpty) return;
    final action = _redoStack.removeLast();
    if (action is AddStrokeAction) {
      _strokes.add(action.stroke);
      _undoStack.add(action);
    } else if (action is ClearAction) {
      _strokes.clear();
      _undoStack.add(action);
    }
    setState(() {});
    widget.onStrokesChanged?.call(_strokes);
  }

  /// 清除所有笔迹
  void clearAll() {
    if (_strokes.isEmpty) return;
    final cleared = List<PadStroke>.from(_strokes);
    _undoStack.add(ClearAction(cleared));
    _strokes.clear();
    _redoStack.clear();
    setState(() {});
    widget.onStrokesChanged?.call(_strokes);
  }

  /// 从BLE点阵笔添加笔画（外部调用）
  void addBleStroke(PadStroke stroke) {
    _strokes.add(stroke);
    _undoStack.add(AddStrokeAction(stroke));
    _redoStack.clear();
    setState(() {});
    widget.onStrokesChanged?.call(_strokes);
  }

  /// 获取所有笔画数据（用于提交）
  List<PadStroke> getStrokes() => List.unmodifiable(_strokes);

  @override
  Widget build(BuildContext context) {
    return Listener(
      // 使用Listener而非GestureDetector，以获取精确的Pointer事件
      onPointerDown: widget.readOnly ? null : _onPointerDown,
      onPointerMove: widget.readOnly ? null : _onPointerMove,
      onPointerUp: widget.readOnly ? null : _onPointerUp,
      child: ClipRect(
        child: CustomPaint(
          painter: _PadStrokePainter(
            strokes: _strokes,
            currentStroke: _currentStroke,
            guideLineType: widget.guideLineType,
          ),
          size: Size.infinite,
        ),
      ),
    );
  }

  /// 触屏落笔
  void _onPointerDown(PointerDownEvent event) {
    final pressure = event.pressure > 0 ? event.pressure : 0.5;
    _currentStroke = PadStroke(
      color: widget.strokeColor,
      baseWidth: widget.strokeWidth,
      source: event.kind == PointerDeviceKind.stylus ? 'stylus' : 'touch',
    );
    _currentStroke!.addPoint(PadStrokePoint(
      x: event.localPosition.dx,
      y: event.localPosition.dy,
      pressure: pressure,
      timestamp: DateTime.now().millisecondsSinceEpoch,
    ));
    setState(() {});
  }

  /// 触屏移动
  void _onPointerMove(PointerMoveEvent event) {
    if (_currentStroke == null) return;
    final pressure = event.pressure > 0 ? event.pressure : 0.5;
    _currentStroke!.addPoint(PadStrokePoint(
      x: event.localPosition.dx,
      y: event.localPosition.dy,
      pressure: pressure,
      timestamp: DateTime.now().millisecondsSinceEpoch,
    ));
    setState(() {});
  }

  /// 触屏抬笔
  void _onPointerUp(PointerUpEvent event) {
    if (_currentStroke == null) return;
    if (_currentStroke!.points.length >= 2) {
      _strokes.add(_currentStroke!);
      _undoStack.add(AddStrokeAction(_currentStroke!));
      _redoStack.clear();
      // 限制撤销栈大小
      if (_undoStack.length > maxUndoSteps) {
        _undoStack.removeAt(0);
      }
      widget.onStrokesChanged?.call(_strokes);
    }
    _currentStroke = null;
    setState(() {});
  }
}

/* ========== Painter实现 ========== */

/// 笔迹绘制Painter
class _PadStrokePainter extends CustomPainter {
  final List<PadStroke> strokes;
  final PadStroke? currentStroke;
  final GuideLineType guideLineType;

  _PadStrokePainter({
    required this.strokes,
    this.currentStroke,
    this.guideLineType = GuideLineType.none,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // 绘制背景
    canvas.drawRect(
      Rect.fromLTWH(0, 0, size.width, size.height),
      Paint()..color = Colors.white,
    );

    // 绘制辅助线
    if (guideLineType != GuideLineType.none) {
      _drawGuideLines(canvas, size);
    }

    // 绘制已完成的笔画
    for (final stroke in strokes) {
      _drawStroke(canvas, stroke);
    }

    // 绘制当前活跃笔画
    if (currentStroke != null) {
      _drawStroke(canvas, currentStroke!);
    }
  }

  /// 绘制辅助线
  void _drawGuideLines(Canvas canvas, Size size) {
    final paint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 0.5;

    switch (guideLineType) {
      case GuideLineType.tianZiGe:
        _drawTianZiGe(canvas, size, paint);
        break;
      case GuideLineType.miZiGe:
        _drawMiZiGe(canvas, size, paint);
        break;
      case GuideLineType.siXianSanGe:
        _drawSiXianSanGe(canvas, size, paint);
        break;
      default:
        break;
    }
  }

  /// 绘制田字格
  void _drawTianZiGe(Canvas canvas, Size size, Paint paint) {
    const cellSize = 80.0;
    paint.color = Colors.red.withValues(alpha: 0.3);

    // 外框（实线）
    for (double x = 0; x <= size.width; x += cellSize) {
      canvas.drawLine(Offset(x, 0), Offset(x, size.height), paint);
    }
    for (double y = 0; y <= size.height; y += cellSize) {
      canvas.drawLine(Offset(0, y), Offset(size.width, y), paint);
    }

    // 中心十字线（虚线效果用半透明）
    paint.color = Colors.red.withValues(alpha: 0.15);
    final halfCell = cellSize / 2;
    for (double x = halfCell; x < size.width; x += cellSize) {
      canvas.drawLine(Offset(x, 0), Offset(x, size.height), paint);
    }
    for (double y = halfCell; y < size.height; y += cellSize) {
      canvas.drawLine(Offset(0, y), Offset(size.width, y), paint);
    }
  }

  /// 绘制米字格
  void _drawMiZiGe(Canvas canvas, Size size, Paint paint) {
    const cellSize = 80.0;
    paint.color = Colors.red.withValues(alpha: 0.3);

    for (double x = 0; x <= size.width; x += cellSize) {
      canvas.drawLine(Offset(x, 0), Offset(x, size.height), paint);
    }
    for (double y = 0; y <= size.height; y += cellSize) {
      canvas.drawLine(Offset(0, y), Offset(size.width, y), paint);
    }

    // 对角线 + 十字线
    paint.color = Colors.red.withValues(alpha: 0.15);
    for (double x = 0; x < size.width; x += cellSize) {
      for (double y = 0; y < size.height; y += cellSize) {
        // 对角线
        canvas.drawLine(Offset(x, y), Offset(x + cellSize, y + cellSize), paint);
        canvas.drawLine(Offset(x + cellSize, y), Offset(x, y + cellSize), paint);
        // 十字线
        canvas.drawLine(Offset(x + cellSize / 2, y), Offset(x + cellSize / 2, y + cellSize), paint);
        canvas.drawLine(Offset(x, y + cellSize / 2), Offset(x + cellSize, y + cellSize / 2), paint);
      }
    }
  }

  /// 绘制四线三格（拼音/英文）
  void _drawSiXianSanGe(Canvas canvas, Size size, Paint paint) {
    const lineSpacing = 15.0;
    const groupHeight = lineSpacing * 3;
    const groupGap = 20.0;

    paint.color = Colors.green.withValues(alpha: 0.3);

    double y = 20;
    while (y < size.height - groupHeight) {
      // 四条横线
      for (int i = 0; i < 4; i++) {
        final lineY = y + i * lineSpacing;
        // 第二条线（中线）用虚线表示
        if (i == 1 || i == 2) {
          paint.color = Colors.green.withValues(alpha: 0.15);
        } else {
          paint.color = Colors.green.withValues(alpha: 0.3);
        }
        canvas.drawLine(Offset(0, lineY), Offset(size.width, lineY), paint);
      }
      y += groupHeight + groupGap;
    }
  }

  /// 绘制单个笔画（贝塞尔平滑 + 压力笔锋）
  void _drawStroke(Canvas canvas, PadStroke stroke) {
    if (stroke.points.length < 2) return;

    final paint = Paint()
      ..color = stroke.color
      ..strokeCap = StrokeCap.round
      ..strokeJoin = StrokeJoin.round
      ..style = PaintingStyle.stroke
      ..isAntiAlias = true;

    for (int i = 1; i < stroke.points.length; i++) {
      final prev = stroke.points[i - 1];
      final curr = stroke.points[i];

      // 压力笔锋宽度计算
      final avgPressure = (prev.pressure + curr.pressure) / 2.0;
      var width = stroke.baseWidth * (0.3 + avgPressure * 1.7);

      // 落笔过渡
      if (i < 5) width *= (i / 5.0);
      // 抬笔过渡
      final remaining = stroke.points.length - i;
      if (remaining < 5) width *= (remaining / 5.0);
      width = max(width, 0.5);

      paint.strokeWidth = width;

      if (i >= 2) {
        // 贝塞尔曲线平滑
        final pp = stroke.points[i - 2];
        final cp1x = prev.x + (curr.x - pp.x) * 0.2;
        final cp1y = prev.y + (curr.y - pp.y) * 0.2;
        final cp2x = curr.x - (curr.x - prev.x) * 0.2;
        final cp2y = curr.y - (curr.y - prev.y) * 0.2;

        final path = Path()
          ..moveTo(prev.x, prev.y)
          ..cubicTo(cp1x, cp1y, cp2x, cp2y, curr.x, curr.y);
        canvas.drawPath(path, paint);
      } else {
        canvas.drawLine(Offset(prev.x, prev.y), Offset(curr.x, curr.y), paint);
      }
    }
  }

  @override
  bool shouldRepaint(covariant _PadStrokePainter oldDelegate) {
    return oldDelegate.strokes.length != strokes.length ||
        oldDelegate.currentStroke != currentStroke;
  }
}
