// ===========================================================================
// FILE: lib/ui/game/game_screen.dart
// ===========================================================================

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

import '../../logic/game_controller.dart';
import '../../core/theme_manager.dart';
import '../../core/app_colors.dart';
import 'board_painter.dart';
import 'score_board.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../services/storage_service.dart';

TextStyle _getTextStyle(AppThemeType themeType, TextStyle baseStyle) {
  if (themeType == AppThemeType.doodle) {
    return GoogleFonts.permanentMarker(textStyle: baseStyle);
  } else if (themeType == AppThemeType.arcade) {
    return GoogleFonts.pressStart2p(textStyle: baseStyle.copyWith(
      fontSize: baseStyle.fontSize != null ? baseStyle.fontSize! * 0.75 : null,
      letterSpacing: 0.5,
    ));
  } else if (themeType == AppThemeType.grimorio) {
    return GoogleFonts.cinzelDecorative(textStyle: baseStyle.copyWith(fontWeight: FontWeight.bold));
  }
  return baseStyle;
}

class GameScreen extends StatefulWidget {
  const GameScreen({super.key});

  @override
  State<GameScreen> createState() => _GameScreenState();
}

class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
  late AnimationController _blinkController;
  bool _gameOverDialogShown = false;
  bool _opponentLeftDialogShown = false;

  // Variabili per coprire il posizionamento del Jolly in Locale
  bool _hideJokerMessage = false;
  bool _wasSetupPhase = false;
  Player _lastJokerTurn = Player.red;

  @override
  void initState() {
    super.initState();
    _blinkController = AnimationController(vsync: this, duration: const Duration(milliseconds: 600))..repeat(reverse: true);
  }

  @override
  void dispose() { _blinkController.dispose(); super.dispose(); }

  void _showGameOverDialog(BuildContext context, GameController game, ThemeColors theme, AppThemeType themeType) {
    _gameOverDialogShown = true;

    showDialog(
        barrierDismissible: false,
        context: context,
        builder: (dialogContext) => Consumer<GameController>(
            builder: (context, controller, child) {
              if (!controller.isGameOver) {
                WidgetsBinding.instance.addPostFrameCallback((_) {
                  if (_gameOverDialogShown) {
                    _gameOverDialogShown = false;
                    if (Navigator.canPop(dialogContext)) Navigator.pop(dialogContext);
                  }
                });
                return const SizedBox.shrink();
              }

              int red = controller.board.scoreRed; int blue = controller.board.scoreBlue;
              bool playerBeatCPU = controller.isVsCPU && red > blue;

              String myName = StorageService.instance.playerName.toUpperCase();
              if (myName.isEmpty) myName = "TU";

              String nameRed = controller.isOnline ? controller.onlineHostName.toUpperCase() : myName;
              String nameBlue = controller.isOnline ? controller.onlineGuestName.toUpperCase() : (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? "VERDE" : "BLU");
              if (controller.isVsCPU) nameBlue = "CPU";

              String winnerText = ""; Color winnerColor = theme.text;
              if (red > blue) { winnerText = "VINCE $nameRed!"; winnerColor = theme.playerRed; }
              else if (blue > red) { winnerText = "VINCE $nameBlue!"; winnerColor = theme.playerBlue; }
              else { winnerText = "PAREGGIO!"; winnerColor = theme.text; }

              return AlertDialog(
                backgroundColor: theme.background,
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20), side: BorderSide(color: winnerColor.withOpacity(0.5), width: 2)),
                title: Text("FINE PARTITA", textAlign: TextAlign.center, style: _getTextStyle(themeType, TextStyle(color: theme.text, fontWeight: FontWeight.bold, fontSize: 22))),
                content: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Text(winnerText, textAlign: TextAlign.center, style: _getTextStyle(themeType, TextStyle(fontSize: 26, fontWeight: FontWeight.w900, color: winnerColor))),
                    const SizedBox(height: 20),
                    Container(
                      padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
                      decoration: BoxDecoration(color: theme.text.withOpacity(0.05), borderRadius: BorderRadius.circular(15)),
                      // AGGIUNTO FITTEDBOX QUI
                      child: FittedBox(
                        fit: BoxFit.scaleDown,
                        child: Row(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            Text("$nameRed: $red", style: _getTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: theme.playerRed))),
                            Text("  -  ", style: _getTextStyle(themeType, TextStyle(fontSize: 18, color: theme.text))),
                            Text("$nameBlue: $blue", style: _getTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: theme.playerBlue))),
                          ],
                        ),
                      ),
                    ),
                    if (controller.lastMatchXP > 0) ...[
                      const SizedBox(height: 15),
                      Container(
                        padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
                        decoration: BoxDecoration(
                          color: Colors.green.withOpacity(0.15),
                          borderRadius: BorderRadius.circular(20),
                          border: Border.all(color: Colors.greenAccent, width: 1.5),
                          boxShadow: themeType == AppThemeType.cyberpunk ? [const BoxShadow(color: Colors.greenAccent, blurRadius: 10, spreadRadius: -5)] : [],
                        ),
                        child: Text("+ ${controller.lastMatchXP} XP", style: _getTextStyle(themeType, const TextStyle(color: Colors.greenAccent, fontWeight: FontWeight.w900, fontSize: 16, letterSpacing: 1.5))),
                      ),
                    ],

                    if (controller.isVsCPU) ...[
                      const SizedBox(height: 15),
                      Text("Difficoltà CPU: Livello ${controller.cpuLevel}", style: _getTextStyle(themeType, TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: theme.text.withOpacity(0.7)))),
                    ],
                    if (controller.isOnline) ...[
                      const SizedBox(height: 20),
                      if (controller.rematchRequested && !controller.opponentWantsRematch)
                        Text("In attesa di $nameBlue...", style: _getTextStyle(themeType, const TextStyle(color: Colors.amber, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic))),
                      if (controller.opponentWantsRematch && !controller.rematchRequested)
                        Text("$nameBlue vuole la rivincita!", style: _getTextStyle(themeType, const TextStyle(color: Colors.greenAccent, fontWeight: FontWeight.bold))),
                      if (controller.rematchRequested && controller.opponentWantsRematch)
                        Text("Avvio nuova partita...", style: _getTextStyle(themeType, const TextStyle(color: Colors.green, fontWeight: FontWeight.bold))),
                    ]
                  ],
                ),
                actionsPadding: const EdgeInsets.only(left: 20, right: 20, bottom: 20, top: 10),
                actionsAlignment: MainAxisAlignment.center,
                actions: [
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                      if (playerBeatCPU)
                        ElevatedButton(
                          style: ElevatedButton.styleFrom(backgroundColor: winnerColor, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 15), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)), elevation: 5),
                          onPressed: () { controller.increaseLevelAndRestart(); },
                          child: Text("PROSSIMO LIVELLO ➔", style: _getTextStyle(themeType, const TextStyle(fontWeight: FontWeight.bold, fontSize: 16))),
                        )
                      else if (controller.isOnline)
                        ElevatedButton(
                          style: ElevatedButton.styleFrom(backgroundColor: controller.rematchRequested ? Colors.grey : (winnerColor == theme.text ? theme.playerBlue : winnerColor), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 15), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)), elevation: 5),
                          onPressed: controller.rematchRequested ? null : () { controller.requestRematch(); },
                          child: Text(controller.opponentWantsRematch ? "ACCETTA RIVINCITA" : "CHIEDI RIVINCITA", style: _getTextStyle(themeType, const TextStyle(fontWeight: FontWeight.bold, fontSize: 16, letterSpacing: 1.0))),
                        )
                      else
                        ElevatedButton(
                          style: ElevatedButton.styleFrom(backgroundColor: winnerColor == theme.text ? theme.playerBlue : winnerColor, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 15), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)), elevation: 5),
                          onPressed: () { controller.startNewGame(controller.board.radius, vsCPU: controller.isVsCPU, shape: controller.board.shape, timeMode: controller.isTimeMode); },
                          child: Text("RIGIOCA", style: _getTextStyle(themeType, const TextStyle(fontWeight: FontWeight.bold, fontSize: 16, letterSpacing: 2))),
                        ),
                      const SizedBox(height: 12),
                      OutlinedButton(
                        style: OutlinedButton.styleFrom(foregroundColor: theme.text, side: BorderSide(color: theme.text.withOpacity(0.3), width: 2), padding: const EdgeInsets.symmetric(vertical: 15), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15))),
                        onPressed: () {
                          if (controller.isOnline) controller.disconnectOnlineGame();
                          _gameOverDialogShown = false;
                          Navigator.pop(dialogContext); Navigator.pop(context);
                        },
                        child: Text("TORNA AL MENU", style: _getTextStyle(themeType, TextStyle(fontWeight: FontWeight.bold, color: theme.text, fontSize: 14, letterSpacing: 1.5))),
                      ),
                    ],
                  )
                ],
              );
            }
        )
    );
  }

  Widget _buildThemedJokerMessage(ThemeColors theme, AppThemeType themeType, GameController gameController) {
    String titleText = "";
    String subtitleText = "";

    if (gameController.isOnline) {
      titleText = gameController.myJokerPlaced ? "In attesa dell'avversario..." : "Nascondi il tuo Jolly!";
      subtitleText = gameController.myJokerPlaced ? "" : "(Tocca qui per nascondere)";
    } else if (gameController.isVsCPU) {
      titleText = "Nascondi il tuo Jolly!";
      subtitleText = "(Tocca qui per nascondere)";
    } else {
      // --- TESTI MODALITÀ LOCALE ---
      String pName = gameController.jokerTurn == Player.red ? "ROSSO" : (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? "VERDE" : "BLU");
      titleText = "TURNO GIOCATORE $pName";
      subtitleText = "Passa il dispositivo.\nL'avversario NON deve guardare!\n\n(Tocca qui quando sei pronto)";
    }

    Widget content = Padding(
      padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 25),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(ThemeIcons.joker(themeType), color: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? Colors.yellowAccent : theme.playerBlue, size: 50),
          const SizedBox(height: 15),
          Text(
            titleText,
            textAlign: TextAlign.center,
            style: _getTextStyle(themeType, TextStyle(
              color: themeType == AppThemeType.doodle ? Colors.black87 : theme.text,
              fontSize: 20,
              fontWeight: FontWeight.bold,
            )),
          ),
          const SizedBox(height: 25),
          Text(
            subtitleText,
            textAlign: TextAlign.center,
            style: _getTextStyle(themeType, TextStyle(
                color: themeType == AppThemeType.doodle ? Colors.black54 : theme.text.withOpacity(0.6),
                fontSize: 12,
                height: 1.5
            )),
          ),
        ],
      ),
    );

    if (themeType == AppThemeType.cyberpunk) {
      return Container(decoration: BoxDecoration(color: Colors.black.withOpacity(0.9), borderRadius: BorderRadius.circular(20), border: Border.all(color: Colors.yellowAccent, width: 2), boxShadow: [const BoxShadow(color: Colors.yellowAccent, blurRadius: 15, spreadRadius: 0)]), child: content);
    } else if (themeType == AppThemeType.doodle) {
      return Container(decoration: BoxDecoration(color: const Color(0xFFF9F9F9), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.black87, width: 3), boxShadow: const [BoxShadow(color: Colors.black26, offset: Offset(6, 6))]), child: content);
    } else if (themeType == AppThemeType.wood) {
      return Container(decoration: BoxDecoration(color: const Color(0xFF5D4037), borderRadius: BorderRadius.circular(15), border: Border.all(color: const Color(0xFF3E2723), width: 4), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.6), blurRadius: 15, offset: const Offset(0, 8))]), child: content);
    } else if (themeType == AppThemeType.arcade) {
      return Container(decoration: BoxDecoration(color: Colors.black, borderRadius: BorderRadius.zero, border: Border.all(color: Colors.greenAccent, width: 4)), child: content);
    } else if (themeType == AppThemeType.grimorio) {
      return Container(decoration: BoxDecoration(color: const Color(0xFF2C1E3D), borderRadius: BorderRadius.circular(30), border: Border.all(color: const Color(0xFFBCAAA4), width: 3), boxShadow: [BoxShadow(color: Colors.deepPurpleAccent.withOpacity(0.5), blurRadius: 20, spreadRadius: 5)]), child: content);
    } else {
      return Container(decoration: BoxDecoration(color: theme.background, borderRadius: BorderRadius.circular(20), border: Border.all(color: theme.gridLine, width: 2), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.15), blurRadius: 20, offset: const Offset(0, 10))]), child: content);
    }
  }

  @override
  Widget build(BuildContext context) {
    final themeManager = context.watch<ThemeManager>();
    final themeType = themeManager.currentThemeType;
    final theme = themeManager.currentColors;
    final gameController = context.watch<GameController>();

    // --- LOGICA CAMBIO TURNO E SCHERMATA JOLLY ---
    if (gameController.isSetupPhase && !_wasSetupPhase) {
      // È appena iniziata una nuova partita
      _hideJokerMessage = false;
      _lastJokerTurn = Player.red;
    } else if (gameController.isSetupPhase && gameController.jokerTurn != _lastJokerTurn) {
      // È cambiato il turno durante il setup (in modalità locale), rifacciamo apparire la copertura
      _hideJokerMessage = false;
      _lastJokerTurn = gameController.jokerTurn;
    }
    _wasSetupPhase = gameController.isSetupPhase;

    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (gameController.opponentLeft && !_opponentLeftDialogShown) {
        _opponentLeftDialogShown = true;
        showDialog(
            barrierDismissible: false,
            context: context,
            builder: (dialogContext) => AlertDialog(
              backgroundColor: theme.background,
              shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
              title: Text("VITTORIA A TAVOLINO!", textAlign: TextAlign.center, style: _getTextStyle(themeType, TextStyle(color: theme.playerRed, fontWeight: FontWeight.bold))),
              content: Text("L'avversario ha abbandonato la stanza.\nSei il vincitore incontestato!", textAlign: TextAlign.center, style: _getTextStyle(themeType, TextStyle(color: theme.text, fontSize: 16))),
              actionsAlignment: MainAxisAlignment.center,
              actions: [
                ElevatedButton(
                  style: ElevatedButton.styleFrom(backgroundColor: theme.playerBlue, foregroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15))),
                  onPressed: () { gameController.disconnectOnlineGame(); Navigator.pop(dialogContext); Navigator.pop(context); },
                  child: Text("MENU PRINCIPALE", style: _getTextStyle(themeType, const TextStyle(fontWeight: FontWeight.bold))),
                )
              ],
            )
        );
      } else if (gameController.board.isGameOver && !_gameOverDialogShown) {
        _showGameOverDialog(context, gameController, theme, themeType);
      }
    });

    String? bgImage;
    if (themeType == AppThemeType.wood) bgImage = 'assets/images/wood_bg.jpg';
    if (themeType == AppThemeType.doodle) bgImage = 'assets/images/doodle_bg.jpg';

    Color indicatorColor = themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? Colors.white : Colors.black;

    Widget emojiBar = const SizedBox();
    if (gameController.isOnline && !gameController.isGameOver) {
      final List<String> emojis = ['😂', '😡', '😱', '🥳', '👀'];
      emojiBar = Container(
        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
        decoration: BoxDecoration(
          color: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? Colors.black.withOpacity(0.6) : Colors.white.withOpacity(0.8),
          borderRadius: BorderRadius.circular(30),
          border: Border.all(color: themeType == AppThemeType.cyberpunk ? theme.playerBlue.withOpacity(0.3) : Colors.black12, width: 2),
        ),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: emojis.map((e) => GestureDetector(
            onTap: () => gameController.sendReaction(e),
            child: Padding(padding: const EdgeInsets.symmetric(horizontal: 6), child: Text(e, style: const TextStyle(fontSize: 22))),
          )).toList(),
        ),
      );
    }

    Widget gameContent = SafeArea(
      child: Stack(
        children: [
          Column(
            children: [
              const ScoreBoard(),
              Expanded(
                child: Center(
                  child: Padding(
                    padding: const EdgeInsets.all(10.0),
                    child: LayoutBuilder(
                        builder: (context, constraints) {
                          int cols = gameController.board.columns + 1;
                          int rows = gameController.board.rows + 1;
                          double boxSize = constraints.maxWidth / cols;
                          double requiredHeight = boxSize * rows;
                          if (requiredHeight > constraints.maxHeight) { boxSize = constraints.maxHeight / rows; }
                          double actualWidth = boxSize * cols;
                          double actualHeight = boxSize * rows;

                          return SizedBox(
                            width: actualWidth, height: actualHeight,
                            child: GestureDetector(
                              behavior: HitTestBehavior.opaque,
                              onTapDown: (details) => _handleTap(details.localPosition, actualWidth, actualHeight, gameController, themeType),
                              child: AnimatedBuilder(
                                  animation: _blinkController,
                                  builder: (context, child) {
                                    return CustomPaint(
                                      size: Size(actualWidth, actualHeight),
                                      painter: BoardPainter(
                                        board: gameController.board, theme: theme, themeType: themeType,
                                        blinkValue: _blinkController.value, isOnline: gameController.isOnline,
                                        isVsCPU: gameController.isVsCPU, isSetupPhase: gameController.isSetupPhase,
                                        myPlayer: gameController.myPlayer, jokerTurn: gameController.jokerTurn,
                                      ),
                                    );
                                  }
                              ),
                            ),
                          );
                        }
                    ),
                  ),
                ),
              ),

              Padding(
                padding: const EdgeInsets.only(bottom: 20.0, left: 20.0, right: 20.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    if (gameController.isVsCPU)
                      Container(
                        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                        decoration: BoxDecoration(color: indicatorColor.withOpacity(0.1), borderRadius: BorderRadius.circular(20), border: Border.all(color: indicatorColor.withOpacity(0.3))),
                        child: Row(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            Icon(Icons.smart_toy_rounded, size: 16, color: indicatorColor), const SizedBox(width: 8),
                            Text("LIVELLO CPU: ${gameController.cpuLevel}", style: _getTextStyle(themeType, TextStyle(color: indicatorColor, fontWeight: FontWeight.bold, fontSize: 11, letterSpacing: 1.0))),
                          ],
                        ),
                      )
                    else
                      emojiBar,

                    Container(
                      decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.4), offset: const Offset(0, 4), blurRadius: 5)]),
                      child: TextButton.icon(
                        style: TextButton.styleFrom(backgroundColor: bgImage != null || themeType == AppThemeType.arcade ? Colors.black87 : theme.background, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20), side: BorderSide(color: Colors.white.withOpacity(0.1), width: 1))),
                        icon: Icon(Icons.exit_to_app, color: bgImage != null || themeType == AppThemeType.arcade ? Colors.white : theme.text, size: 20),
                        onPressed: () { gameController.disconnectOnlineGame(); Navigator.pop(context); },
                        label: Text("ESCI", style: _getTextStyle(themeType, TextStyle(color: bgImage != null || themeType == AppThemeType.arcade ? Colors.white : theme.text, fontWeight: FontWeight.bold, fontSize: 12))),
                      ),
                    ),
                  ],
                ),
              )
            ],
          ),

          if (gameController.myReaction != null)
            Positioned(top: 80, left: gameController.isHost ? 30 : null, right: gameController.isHost ? null : 30, child: _BouncingEmoji(emoji: gameController.myReaction!)),
          if (gameController.opponentReaction != null)
            Positioned(top: 80, left: !gameController.isHost ? 30 : null, right: !gameController.isHost ? null : 30, child: _BouncingEmoji(emoji: gameController.opponentReaction!)),
        ],
      ),
    );

    return PopScope(
      canPop: true,
      onPopInvoked: (didPop) { gameController.disconnectOnlineGame(); },
      child: Scaffold(
        backgroundColor: bgImage != null ? Colors.transparent : theme.background,
        body: CustomPaint(
          painter: themeType == AppThemeType.minimal ? FullScreenGridPainter(Colors.black.withOpacity(0.06)) : null,
          child: Container(
            decoration: bgImage != null ? BoxDecoration(image: DecorationImage(image: AssetImage(bgImage), fit: BoxFit.cover, colorFilter: themeType == AppThemeType.doodle ? ColorFilter.mode(Colors.white.withOpacity(0.7), BlendMode.lighten) : null)) : null,
            child: Stack(
              children: [
                if (gameController.isTimeMode && !gameController.isCPUThinking && !gameController.isGameOver && gameController.timeLeft > 0 && gameController.timeLeft <= 5 && !gameController.isSetupPhase)
                  Positioned.fill(child: BlitzBackgroundEffect(timeLeft: gameController.timeLeft, color: theme.playerRed, themeType: themeType)),

                if (gameController.effectText.isNotEmpty)
                  Positioned.fill(child: SpecialEventBackgroundEffect(text: gameController.effectText, color: gameController.effectColor, themeType: themeType)),

                Positioned.fill(child: gameContent),

                // --- SCHERMATA COPRENTE PER IL PASSAGGIO DEL TELEFONO IN LOCALE ---
                if (gameController.isSetupPhase && !_hideJokerMessage)
                  Positioned.fill(
                    child: Container(
                      // Il colore di sfondo riempie tutto lo schermo per non far sbirciare la griglia
                      color: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade
                          ? Colors.black
                          : theme.background.withOpacity(0.98),
                      child: Center(
                        child: Padding(
                          padding: const EdgeInsets.symmetric(horizontal: 30.0),
                          child: GestureDetector(
                            onTap: () { setState(() { _hideJokerMessage = true; }); },
                            child: Material(color: Colors.transparent, child: _buildThemedJokerMessage(theme, themeType, gameController)),
                          ),
                        ),
                      ),
                    ),
                  ),

                if (gameController.isGameOver && gameController.board.scoreRed != gameController.board.scoreBlue)
                  Positioned.fill(child: IgnorePointer(child: WinnerVFXOverlay(winnerColor: gameController.board.scoreRed > gameController.board.scoreBlue ? theme.playerRed : theme.playerBlue, themeType: themeType))),
              ],
            ),
          ),
        ),
      ),
    );
  }

  void _handleTap(Offset tapPos, double width, double height, GameController controller, AppThemeType themeType) {
    final board = controller.board;
    if (board.isGameOver) return;
    int cols = board.columns + 1; double spacing = width / cols; double offset = spacing / 2;

    if (controller.isSetupPhase) {
      int bx = ((tapPos.dx - offset) / spacing).floor(); int by = ((tapPos.dy - offset) / spacing).floor();
      controller.placeJoker(bx, by); return;
    }

    Line? closestLine; double minDistance = double.infinity; double maxTouchDistance = spacing * 0.4;
    for (var line in board.lines) {
      if (line.owner != Player.none || !line.isPlayable) continue;
      Offset screenP1 = Offset(line.p1.x * spacing + offset, line.p1.y * spacing + offset);
      Offset screenP2 = Offset(line.p2.x * spacing + offset, line.p2.y * spacing + offset);
      double dist = _distanceToSegment(tapPos, screenP1, screenP2);
      if (dist < minDistance && dist < maxTouchDistance) { minDistance = dist; closestLine = line; }
    }
    if (closestLine != null) { controller.handleLineTap(closestLine, themeType); }
  }

  double _distanceToSegment(Offset p, Offset a, Offset b) {
    double l2 = (a.dx - b.dx) * (a.dx - b.dx) + (a.dy - b.dy) * (a.dy - b.dy);
    if (l2 == 0) return (p - a).distance;
    double t = (((p.dx - a.dx) * (b.dx - a.dx) + (p.dy - a.dy) * (b.dy - a.dy)) / l2).clamp(0.0, 1.0);
    Offset projection = Offset(a.dx + t * (b.dx - a.dx), a.dy + t * (b.dy - a.dy));
    return (p - projection).distance;
  }
}

class _Particle {
  double x, y, vx, vy, size, angle, spin;
  Color color; int type;
  _Particle({required this.x, required this.y, required this.vx, required this.vy, required this.color, required this.size, required this.angle, required this.spin, required this.type});
}

class WinnerVFXOverlay extends StatefulWidget {
  final Color winnerColor; final AppThemeType themeType;
  const WinnerVFXOverlay({super.key, required this.winnerColor, required this.themeType});
  @override State<WinnerVFXOverlay> createState() => _WinnerVFXOverlayState();
}

class _WinnerVFXOverlayState extends State<WinnerVFXOverlay> with SingleTickerProviderStateMixin {
  late AnimationController _vfxController;
  final List<_Particle> _particles = [];
  final math.Random _rand = math.Random();
  bool _initialized = false;

  @override
  void initState() {
    super.initState();
    _vfxController = AnimationController(vsync: this, duration: const Duration(seconds: 4))..addListener(() { _updateParticles(); })..forward();
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    if (!_initialized) { _initParticles(MediaQuery.of(context).size); _initialized = true; }
  }

  void _initParticles(Size screenSize) {
    int particleCount = widget.themeType == AppThemeType.cyberpunk ? 150 : 100;
    if (widget.themeType == AppThemeType.arcade) particleCount = 80;
    if (widget.themeType == AppThemeType.grimorio) particleCount = 120;

    List<Color> palette = [widget.winnerColor, widget.winnerColor.withOpacity(0.7), Colors.white];
    if (widget.themeType == AppThemeType.cyberpunk) { palette.add(Colors.cyanAccent); palette.add(Colors.yellowAccent); }
    else if (widget.themeType == AppThemeType.doodle) { palette.add(const Color(0xFF00008B)); palette.add(Colors.redAccent); }
    else if (widget.themeType == AppThemeType.wood) { palette = [Colors.orangeAccent, Colors.yellow, Colors.red, Colors.white]; }
    else if (widget.themeType == AppThemeType.arcade) { palette = [widget.winnerColor, Colors.white, Colors.greenAccent]; }
    else if (widget.themeType == AppThemeType.grimorio) { palette = [widget.winnerColor, Colors.deepPurpleAccent, Colors.white]; }

    for (int i = 0; i < particleCount; i++) {
      double speed = _rand.nextDouble() * 20 + 5;
      double theta = _rand.nextDouble() * 2 * math.pi;
      _particles.add(_Particle(x: screenSize.width / 2, y: screenSize.height / 2, vx: speed * math.cos(theta), vy: speed * math.sin(theta) - 5, color: palette[_rand.nextInt(palette.length)], size: _rand.nextDouble() * 10 + 6, angle: _rand.nextDouble() * math.pi, spin: (_rand.nextDouble() - 0.5) * 0.5, type: _rand.nextInt(3)));
    }
  }

  void _updateParticles() {
    setState(() {
      for (var p in _particles) {
        p.x += p.vx; p.y += p.vy;
        if (widget.themeType == AppThemeType.cyberpunk) { p.vy += 0.1; p.vx *= 0.98; p.vy *= 0.98; }
        else if (widget.themeType == AppThemeType.wood) { p.vy -= 0.2; p.x += math.sin(p.y * 0.05) * 2; }
        else if (widget.themeType == AppThemeType.arcade) { p.vy += 0.3; p.spin = 0; p.angle = 0; }
        else if (widget.themeType == AppThemeType.grimorio) { p.vy -= 0.1; p.x += math.sin(p.y * 0.02) * 1.5; p.size *= 0.995; }
        else { p.vy += 0.5; }
        p.angle += p.spin; p.size *= 0.99;
      }
    });
  }

  @override void dispose() { _vfxController.dispose(); super.dispose(); }
  @override Widget build(BuildContext context) { return CustomPaint(painter: _VFXPainter(particles: _particles, themeType: widget.themeType), child: Container()); }
}

class _VFXPainter extends CustomPainter {
  final List<_Particle> particles; final AppThemeType themeType;
  _VFXPainter({required this.particles, required this.themeType});

  @override
  void paint(Canvas canvas, Size size) {
    for (var p in particles) {
      if (p.size < 0.5) continue;
      final paint = Paint()..color = p.color..style = PaintingStyle.fill;
      if (themeType == AppThemeType.cyberpunk) { paint.maskFilter = const MaskFilter.blur(BlurStyle.solid, 4.0); }
      canvas.save(); canvas.translate(p.x, p.y); canvas.rotate(p.angle);

      if (themeType == AppThemeType.doodle) {
        paint.style = PaintingStyle.stroke; paint.strokeWidth = 2.0;
        if (p.type == 0) { canvas.drawCircle(Offset.zero, p.size, paint); } else { canvas.drawRect(Rect.fromCenter(center: Offset.zero, width: p.size*2, height: p.size*2), paint); }
      } else if (themeType == AppThemeType.wood) {
        paint.maskFilter = const MaskFilter.blur(BlurStyle.normal, 3.0); canvas.drawCircle(Offset.zero, p.size, paint);
      } else if (themeType == AppThemeType.arcade) {
        canvas.drawRect(Rect.fromCenter(center: Offset.zero, width: p.size * 1.5, height: p.size * 1.5), paint);
      } else if (themeType == AppThemeType.grimorio) {
        paint.maskFilter = const MaskFilter.blur(BlurStyle.normal, 4.0);
        canvas.drawCircle(Offset.zero, p.size, paint);
        canvas.drawCircle(Offset.zero, p.size * 0.3, Paint()..color=Colors.white..style=PaintingStyle.fill);
      } else {
        if (p.type == 0) { canvas.drawCircle(Offset.zero, p.size, paint); }
        else if (p.type == 1) { canvas.drawRect(Rect.fromCenter(center: Offset.zero, width: p.size * 2, height: p.size * 2), paint); }
        else { var path = Path()..moveTo(0, -p.size)..lineTo(p.size, p.size)..lineTo(-p.size, p.size)..close(); canvas.drawPath(path, paint); }
      }
      canvas.restore();
    }
  }
  @override bool shouldRepaint(covariant _VFXPainter oldDelegate) => true;
}

class _BouncingEmoji extends StatefulWidget {
  final String emoji; const _BouncingEmoji({required this.emoji});
  @override State<_BouncingEmoji> createState() => _BouncingEmojiState();
}

class _BouncingEmojiState extends State<_BouncingEmoji> with SingleTickerProviderStateMixin {
  late AnimationController _ctrl; late Animation<double> _anim;
  @override void initState() { super.initState(); _ctrl = AnimationController(vsync: this, duration: const Duration(milliseconds: 500))..repeat(reverse: true); _anim = Tween<double>(begin: -10, end: 10).animate(CurvedAnimation(parent: _ctrl, curve: Curves.easeInOut)); }
  @override void dispose() { _ctrl.dispose(); super.dispose(); }
  @override Widget build(BuildContext context) { return AnimatedBuilder(animation: _anim, builder: (ctx, child) => Transform.translate(offset: Offset(0, _anim.value), child: Container(padding: const EdgeInsets.all(8), decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle, boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 5)]), child: Text(widget.emoji, style: const TextStyle(fontSize: 32))))); }
}

class FullScreenGridPainter extends CustomPainter {
  final Color gridColor; FullScreenGridPainter(this.gridColor);
  @override void paint(Canvas canvas, Size size) { final Paint paperGridPaint = Paint()..color = gridColor..strokeWidth = 1.0..style = PaintingStyle.stroke; double paperStep = 20.0; for (double i = 0; i <= size.width; i += paperStep) canvas.drawLine(Offset(i, 0), Offset(i, size.height), paperGridPaint); for (double i = 0; i <= size.height; i += paperStep) canvas.drawLine(Offset(0, i), Offset(size.width, i), paperGridPaint); }
  @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

class BlitzBackgroundEffect extends StatefulWidget {
  final int timeLeft; final Color color; final AppThemeType themeType;
  const BlitzBackgroundEffect({super.key, required this.timeLeft, required this.color, required this.themeType});
  @override State<BlitzBackgroundEffect> createState() => _BlitzBackgroundEffectState();
}
class _BlitzBackgroundEffectState extends State<BlitzBackgroundEffect> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  @override void initState() { super.initState(); _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 400))..repeat(reverse: true); }
  @override void dispose() { _controller.dispose(); super.dispose(); }
  @override Widget build(BuildContext context) { return AnimatedBuilder(animation: _controller, builder: (context, child) { return Container(color: widget.color.withOpacity(0.12 * _controller.value), child: Center(child: ImageFiltered(imageFilter: ImageFilter.blur(sigmaX: 2.0, sigmaY: 2.0), child: Text('${widget.timeLeft}', style: _getTextStyle(widget.themeType, TextStyle(fontSize: 300, fontWeight: FontWeight.w900, color: widget.color.withOpacity(0.35 + (0.3 * _controller.value)), height: 1.0)))))); }); }
}

class SpecialEventBackgroundEffect extends StatefulWidget {
  final String text; final Color color; final AppThemeType themeType;
  const SpecialEventBackgroundEffect({super.key, required this.text, required this.color, required this.themeType});
  @override State<SpecialEventBackgroundEffect> createState() => _SpecialEventBackgroundEffectState();
}
class _SpecialEventBackgroundEffectState extends State<SpecialEventBackgroundEffect> with SingleTickerProviderStateMixin {
  late AnimationController _controller; late Animation<double> _scaleAnimation; late Animation<double> _opacityAnimation;
  @override void initState() { super.initState(); _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 1000))..forward(); _scaleAnimation = Tween<double>(begin: 0.5, end: 1.5).animate(CurvedAnimation(parent: _controller, curve: Curves.easeOutCubic)); _opacityAnimation = Tween<double>(begin: 0.9, end: 0.0).animate(CurvedAnimation(parent: _controller, curve: Curves.easeIn)); }
  @override void didUpdateWidget(covariant SpecialEventBackgroundEffect oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.text != widget.text) { _controller.reset(); _controller.forward(); } }
  @override void dispose() { _controller.dispose(); super.dispose(); }
  @override Widget build(BuildContext context) { return AnimatedBuilder(animation: _controller, builder: (context, child) { return Center(child: Transform.scale(scale: _scaleAnimation.value, child: Opacity(opacity: _opacityAnimation.value, child: ImageFiltered(imageFilter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0), child: Text(widget.text, textAlign: TextAlign.center, style: _getTextStyle(widget.themeType, TextStyle(fontSize: 150, fontWeight: FontWeight.w900, color: widget.color, height: 1.0))))))); }); }
}