import 'package:flutter/material.dart';

import '../../game/models/cell.dart';
import '../../game/models/grid.dart';
import '../../game/models/piece.dart';
import '../theme/palette.dart';
import 'board_geometry.dart';
import 'piece_painter.dart';
import 'tile_painter.dart';

/// Drag ghost preview: a piece hovering at a snapped anchor.
class GhostSpec {
  const GhostSpec({
    required this.piece,
    required this.anchorX,
    required this.anchorY,
    required this.legal,
  });

  final Piece piece;
  final int anchorX;
  final int anchorY;
  final bool legal;
}

class BoardPainter extends CustomPainter {
  const BoardPainter({
    required this.grid,
    required this.ghost,
    required this.flashProgress,
    required this.flashRows,
    required this.flashCols,
  });

  final GridState grid;
  final GhostSpec? ghost;

  /// 1.0 -> 0.0 while the clear flash fades.
  final double flashProgress;
  final List<int> flashRows;
  final List<int> flashCols;

  @override
  void paint(Canvas canvas, Size size) {
    final geo = BoardGeometry(boardSize: size.width);
    final radius = Radius.circular(geo.cellSize * 0.18);
    final inset = geo.cellSize * 0.05;

    final bg = Paint()..color = GamePalette.boardBackground;
    canvas.drawRRect(
      RRect.fromRectAndRadius(Offset.zero & size, const Radius.circular(12)),
      bg,
    );

    for (var y = 0; y < GridState.size; y++) {
      for (var x = 0; x < GridState.size; x++) {
        final rect = geo.cellRect(x, y).deflate(inset);
        final cell = grid.cellAt(x, y);
        switch (cell.type) {
          case CellType.empty:
            canvas.drawRRect(
              RRect.fromRectAndRadius(rect, radius),
              Paint()..color = GamePalette.emptyCell,
            );
          case CellType.filled:
            paintGlossyTile(canvas, rect, GamePalette.tile(cell.colorId));
          case CellType.gem:
            canvas.drawRRect(
              RRect.fromRectAndRadius(rect, radius),
              Paint()..color = GamePalette.emptyCell,
            );
            _paintGem(canvas, rect);
        }
      }
    }

    final g = ghost;
    if (g != null) {
      paintPiece(
        canvas,
        g.piece,
        cellSize: geo.cellSize,
        origin: Offset(g.anchorX * geo.cellSize, g.anchorY * geo.cellSize),
        overrideColor:
            g.legal ? GamePalette.ghostLegal : GamePalette.ghostIllegal,
      );
    }

    if (flashProgress > 0) {
      final flash = Paint()
        ..color = Colors.white.withValues(alpha: 0.75 * flashProgress);
      for (final y in flashRows) {
        canvas.drawRect(
          Rect.fromLTWH(0, y * geo.cellSize, size.width, geo.cellSize),
          flash,
        );
      }
      for (final x in flashCols) {
        canvas.drawRect(
          Rect.fromLTWH(x * geo.cellSize, 0, geo.cellSize, size.height),
          flash,
        );
      }
    }
  }

  void _paintGem(Canvas canvas, Rect rect) {
    final glowPaint = Paint()
      ..color = GamePalette.gem.withValues(alpha: 0.45)
      ..maskFilter = MaskFilter.blur(BlurStyle.normal, rect.width * 0.25);
    canvas.drawCircle(rect.center, rect.width * 0.32, glowPaint);
    final center = rect.center;
    final r = rect.width * 0.32;
    final path = Path()
      ..moveTo(center.dx, center.dy - r)
      ..lineTo(center.dx + r, center.dy)
      ..lineTo(center.dx, center.dy + r)
      ..lineTo(center.dx - r, center.dy)
      ..close();
    canvas.drawPath(path, Paint()..color = GamePalette.gem);
    canvas.drawPath(
      path,
      Paint()
        ..color = Colors.white.withValues(alpha: 0.6)
        ..style = PaintingStyle.stroke
        ..strokeWidth = rect.width * 0.05,
    );
  }

  @override
  bool shouldRepaint(BoardPainter old) =>
      old.grid != grid ||
      old.ghost != ghost ||
      old.flashProgress != flashProgress ||
      old.flashRows != flashRows ||
      old.flashCols != flashCols;
}
