// board_painter.dart

import 'dart:typed_data';

import 'package:flutter/material.dart';

import 'package:puzzleweave/play/board.dart';
import 'package:puzzleweave/play/piece.dart';
import 'package:puzzleweave/skin/skin.dart';
import 'package:logging/logging.dart';

final Logger _log = Logger('board_painter.dart');

class BoardPainter extends CustomPainter {
  final Board board;
  final AnimationController prepareAnimation;

  // 碎片边框宽度
  static const double _pieceStrokeWidth = 1.0;

  // 边框画笔 (外边框，黑色)
  final Paint _outerBorderPaint = Paint()
    ..color = SkinHelper.outLineBorderColor
    ..style = PaintingStyle.stroke
    ..strokeWidth = _pieceStrokeWidth
    ..isAntiAlias = true;

  // 边框画笔 (内边框，白色)
  final Paint _innerBorderPaint = Paint()
    ..color = SkinHelper.innerLineBorderColor
    ..style = PaintingStyle.stroke
    ..strokeWidth = _pieceStrokeWidth
    ..isAntiAlias = true;

  BoardPainter({required this.board, required this.prepareAnimation}) : super(repaint: Listenable.merge([board.boardNotifier, prepareAnimation])); // 触发重绘

  @override
  void paint(Canvas canvas, Size size) {
    switch (board.status) {
      case BoardStatus.loading:
        _paintLoading(canvas, size);
        break;
      case BoardStatus.preparing:
        _paintPreparing(canvas, size);
        break;
      case BoardStatus.shuffle:
        _paintShuffle(canvas, size);
        break;
      case BoardStatus.playing:
        _paintPlaying(canvas, size);
        break;
      case BoardStatus.success:
        _paintSuccess(canvas, size);
        break;
    }
  }

  _paintLoading(Canvas canvas, Size size) {
    // _log.info('_paintLoading');
    // 绘制整个背景底色
    canvas.drawRect(
      Rect.fromLTWH(0, 0, size.width, size.height),
      Paint()
        ..color = SkinHelper.wholeBgColor
        ..style = PaintingStyle.fill,
    );
  }

  _paintPreparing(Canvas canvas, Size size) {
    // _log.info('_paintPreparing');
    // 绘制整个背景底色， 但不绘制核心宫格游戏区
    canvas.drawRect(
      Rect.fromLTWH(0, 0, size.width, size.height),
      Paint()
        ..color = SkinHelper.wholeBgColor
        ..style = PaintingStyle.fill,
    );
    if (prepareAnimation.isAnimating) {
      _paintBackground(canvas, size, (prepareAnimation.value * 255).toInt());
    } else {
      _paintBackground(canvas, size, 255);
    }
  }

  _paintShuffle(Canvas canvas, Size size) {
    // _log.info('_paintShuffle');
    // 绘制背景
    if (board.backgroundPicture != null) {
      canvas.drawPicture(board.backgroundPicture!);
    }

    // 绘制所有卡片
    for (final piece in board.pieces) {
      _drawDealingPiece(canvas, size, piece);
    }
  }

  /// 绘制进行中的游戏界面
  _paintPlaying(Canvas canvas, Size size) {
    // _log.info('_paintPlaying');
    // 1. 绘制背景
    if (board.backgroundPicture != null) {
      canvas.drawPicture(board.backgroundPicture!);
    }

    // 2. 收集所有不重复的群组（避免重复绘制）
    // final Set<PieceGroup> drawnGroups = {};
    for (final piece in board.pieces) {
      _drawPiece(canvas, size, piece);
      // if (piece.group != null) {
      //   if (!drawnGroups.contains(piece.group)) {
      //     drawnGroups.add(piece.group!);
      //     // 调用更新后的 _drawGroup 方法
      //     _drawGroup(canvas, size, piece.group!);
      //   }
      // } else {
      //   _drawPiece(canvas, size, piece);
      // }
    }
  }

  _paintSuccess(Canvas canvas, Size size) {
    final cornerRadius = board.cornerRadius;
    final targetRect = board.finalRect;
    final rrect = RRect.fromRectAndRadius(targetRect, Radius.circular(cornerRadius));
    final sourceRect = Rect.fromLTWH(0, 0, board.image.width.toDouble(), board.image.height.toDouble());

    final Paint outerBorderPaint = Paint()
      ..color = SkinHelper.outLineBorderColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1.0
      ..isAntiAlias = true;

    // 边框画笔
    final Paint innerBorderPaint = Paint()
      ..color = SkinHelper.innerLineBorderColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1.0
      ..isAntiAlias = true;

    final outerRRect = RRect.fromRectAndRadius(targetRect.deflate(0.5), Radius.circular(cornerRadius));
    final innerRRect = RRect.fromRectAndRadius(targetRect.deflate(1.5), Radius.circular(cornerRadius));

    // 1. 绘制整个屏幕背景
    canvas.drawRect(
      Rect.fromLTWH(0, 0, size.width, size.height),
      Paint()
        ..color = SkinHelper.wholeBgColor
        ..style = PaintingStyle.fill,
    );

    canvas.save();

    canvas.clipRRect(rrect);

    canvas.drawImageRect(board.image, sourceRect, targetRect, Paint()..isAntiAlias = true);

    canvas.restore();

    // 绘制边框
    canvas.drawRRect(outerRRect, outerBorderPaint);
    canvas.drawRRect(innerRRect, innerBorderPaint);
  }

  void _drawDealingPiece(Canvas canvas, Size size, Piece piece) {
    final w = piece.width;
    final h = piece.height;
    final storage64 = Float64List.fromList(piece.transform.storage);

    canvas.save();
    canvas.transform(storage64); // 应用平移

    // --- 核心改造：完全使用 cardPicture 绘制未翻转的卡牌 ---
    if (!piece.isFlipped && board.cardPicture != null) {
      // 一次 drawPicture 调用完成：图片、裁剪、外边框、内边框
      canvas.drawPicture(board.cardPicture!);
    } else if (piece.isFlipped) {
      // 保持翻转状态的绘制逻辑不变 (这是原始图片碎片，不是卡牌背面)
      final cornerRadius = board.cornerRadius;
      final rrect = RRect.fromRectAndRadius(Rect.fromLTWH(0, 0, w, h), Radius.circular(cornerRadius));

      // 绘制图片 (需要裁剪)
      canvas.save();
      canvas.clipRRect(rrect);
      final Rect dstRect = Rect.fromLTWH(0, 0, w, h);
      canvas.drawImageRect(board.image, piece.sourceRect, dstRect, Paint()..isAntiAlias = true);
      canvas.restore();

      // 绘制边框 (使用动态 Path，因为这可能是连接后的碎片)
      canvas.save(); // 再次保存，用于边框
      // 这里的 transform 已经应用了，所以直接绘制 path
      final List<Path> paths = _getPiecePath(piece);
      final Path outerBorderPath = paths[1];
      final Path innerBorderPath = paths[2];
      canvas.drawPath(outerBorderPath, _outerBorderPaint); // 外边框，黑色
      canvas.drawPath(innerBorderPath, _innerBorderPaint); // 内边框，白色
      canvas.restore();
    }

    canvas.restore(); // 恢复 Canvas 状态 (移除 piece.transform)
  }

  /// 绘制单个碎片
  void _drawPiece(Canvas canvas, Size size, Piece piece) {
    final double w = piece.width;
    final double h = piece.height;

    // 1. 准备变换矩阵和动态 Path
    final Float64List storage64 = Float64List.fromList(piece.transform.storage);
    // 核心：根据 borders 状态动态生成 Path
    final List<Path> paths = _getPiecePath(piece);
    final Path piecePath = paths[0];
    final Path outerBorderPath = paths[1];
    final Path innerBorderPath = paths[2];

    canvas.save();

    canvas.transform(storage64); // 应用平移

    // 裁剪区域：使用动态生成的 Path 来裁剪图片，实现圆角/尖角混合
    canvas.clipPath(piecePath);

    // 绘制图片：只有落在 rrect 内部的部分图片会被绘制
    final Rect dstRect = Rect.fromLTWH(0, 0, w, h);
    canvas.drawImageRect(board.image, piece.sourceRect, dstRect, Paint()..isAntiAlias = true);

    canvas.restore(); // 恢复 Canvas 状态 (移除裁剪和 transform)

    // --- 绘制边框 ---
    // 为了确保边框线宽向外延伸的部分不会被裁剪，我们需要在裁剪区域被移除后重新绘制。
    canvas.save();
    canvas.transform(storage64); // 重新应用平移

    // 绘制碎片边框
    canvas.drawPath(outerBorderPath, _outerBorderPaint); // 外边框，黑色
    canvas.drawPath(innerBorderPath, _innerBorderPaint); // 内边框，白色

    canvas.restore();
  }

  /// 绘制整个群组（核心实现）
  void _drawGroup(Canvas canvas, Size size, PieceGroup group) {
    if (group.pieces.isEmpty) return;

    // 1. 准备群组基础数据
    final topLeftPiece = group.topLeftPiece;
    group.generateGroupPaths(); // 确保路径已生成

    // 2. 群组基准点变换（基于左上角碎片的绝对位置）
    final baseTransform = Float64List.fromList(topLeftPiece.transform.storage);

    // 3. 计算群组内碎片的相对偏移（相对于左上角碎片）
    final minR = topLeftPiece.curRow;
    final minC = topLeftPiece.curCol;
    final pieceWidth = topLeftPiece.width;
    final pieceHeight = topLeftPiece.height;

    // 4. 绘制群组图片（整体裁剪 + 拼接碎片）
    canvas.save();
    canvas.transform(baseTransform); // 移动到群组基准点

    // 4.1 应用群组裁剪路径（确保超出群组范围的内容不显示）
    if (group.groupClipPath != null) {
      canvas.clipPath(group.groupClipPath!);
    }

    // 4.2 绘制群组内所有碎片的图片部分（相对位置拼接）
    for (final piece in group.pieces) {
      // 计算碎片在群组内的相对坐标（相对于左上角碎片）
      final dr = piece.curRow - minR;
      final dc = piece.curCol - minC;
      final dx = dc * pieceWidth;
      final dy = dr * pieceHeight;

      // 绘制碎片图片到群组内的对应位置
      final dstRect = Rect.fromLTWH(dx, dy, pieceWidth, pieceHeight);
      canvas.drawImageRect(board.image, piece.sourceRect, dstRect, Paint()..isAntiAlias = true);
    }

    canvas.restore(); // 恢复裁剪和基准变换

    // 5. 绘制群组边框（外边框 + 内边框）
    canvas.save();
    canvas.transform(baseTransform); // 重新应用基准变换

    if (group.groupOutLinePath != null) {
      canvas.drawPath(group.groupOutLinePath!, _outerBorderPaint);
    }
    if (group.groupInnerLinePath != null) {
      canvas.drawPath(group.groupInnerLinePath!, _innerBorderPaint);
    }

    canvas.restore();
  }

  List<Path> _getPiecePath(Piece piece) {
    // 如果是单个碎片，直接使用 piece 自身的方法获取路径
    if (piece.path == null || piece.outLinePath == null || piece.innerLinePath == null) {
      return piece.generatePaths();
    } else {
      return [piece.path!, piece.outLinePath!, piece.innerLinePath!];
    }
  }

  // 绘制背景(已经被drawPicture取代)
  void _paintBackground(Canvas canvas, Size size, int alpha) {
    final targetRect = board.targetRect;
    final pieceLogicalWidth = board.pieceLogicalWidth;
    final pieceLogicalHeight = board.pieceLogicalHeight;

    // --- 静态绘制配置 ---
    final double cornerRadius = board.cornerRadius;
    const double strokeWidth = 1.0; // 拼图槽位的线宽
    final double halfStroke = strokeWidth / 2.0;

    // 1. 绘制整个屏幕背景
    canvas.drawRect(
      Rect.fromLTWH(0, 0, size.width, size.height),
      Paint()
        ..color = SkinHelper.wholeBgColor
        ..style = PaintingStyle.fill,
    );

    // 2. 绘制每个拼图槽位（圆角矩形）作为背景的一部分 (静态内容)
    final slotFillPaint = Paint()
      ..color = SkinHelper.slotBgColor.withAlpha(alpha)
      ..style = PaintingStyle.fill;

    final slotStrokePaint = Paint()
      ..color = SkinHelper.slotBorderColor.withAlpha(alpha)
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;

    for (int r = 0; r < board.rows; r++) {
      for (int c = 0; c < board.cols; c++) {
        // 计算当前槽位的边界 (Canvas坐标系)
        final left = targetRect.left + c * pieceLogicalWidth;
        final top = targetRect.top + r * pieceLogicalHeight;
        final right = left + pieceLogicalWidth;
        final bottom = top + pieceLogicalHeight;

        // 为了避免描边溢出到相邻槽位，将矩形向内收缩 halfStroke
        final slotRect = Rect.fromLTRB(left + halfStroke, top + halfStroke, right - halfStroke, bottom - halfStroke);

        final slotRRect = RRect.fromRectAndRadius(slotRect, Radius.circular(cornerRadius));

        // 绘制填充
        canvas.drawRRect(slotRRect, slotFillPaint);

        // 绘制描边
        canvas.drawRRect(slotRRect, slotStrokePaint);
      }
    }
  }

  @override
  bool shouldRepaint(covariant BoardPainter oldDelegate) {
    // 检查不可变的核心数据是否发生变化
    if (oldDelegate.board != board || oldDelegate.prepareAnimation != prepareAnimation) {
      return true;
    }

    // 如果 board 和 animation controller 引用没有变化，
    // 由于构造函数中已经添加了监听器，理论上只需要在监听器触发时重绘。
    // 但为了确保，可以比较 board 的状态，因为它决定了执行哪个绘制逻辑。
    return oldDelegate.board.status != board.status;
  }
}
