// ===========================================================================
// FILE: lib/logic/ai_engine.dart
// ===========================================================================

import 'dart:math';
import '../models/game_board.dart';

class _ClosureResult {
  final bool closesSomething;
  final int netValue;
  final bool causesSwap;
  _ClosureResult(this.closesSomething, this.netValue, this.causesSwap);
}

class AIEngine {
  static Line getBestMove(GameBoard board, int level) {
    List<Line> availableLines = board.lines.where((l) => l.owner == Player.none && l.isPlayable).toList();
    final random = Random();

    if (availableLines.isEmpty) return board.lines.first;

    double smartChance = 0.50 + ((level - 1) * 0.10);
    if (smartChance > 1.0) smartChance = 1.0;

    bool beSmart = random.nextDouble() < smartChance;

    int myScore = board.currentPlayer == Player.red ? board.scoreRed : board.scoreBlue;
    int oppScore = board.currentPlayer == Player.red ? board.scoreBlue : board.scoreRed;

    List<Line> goodClosingMoves = [];
    List<Line> badClosingMoves = [];

    for (var line in availableLines) {
      var result = _checkClosure(board, line);
      if (result.closesSomething) {
        if (result.causesSwap) {
          if (myScore < oppScore) {
            goodClosingMoves.add(line);
          } else {
            badClosingMoves.add(line);
          }
        } else {
          if (result.netValue >= 0) {
            goodClosingMoves.add(line);
          } else {
            badClosingMoves.add(line);
          }
        }
      }
    }

    // --- REGOLA 1: Chiudere i quadrati vantaggiosi ---
    if (goodClosingMoves.isNotEmpty) {
      if (beSmart || random.nextDouble() < 0.70) {
        return goodClosingMoves[random.nextInt(goodClosingMoves.length)];
      }
    }

    // --- REGOLA 2: Mosse Sicure ---
    List<Line> safeMoves = [];
    for (var line in availableLines) {
      if (!badClosingMoves.contains(line) && !goodClosingMoves.contains(line) && _isSafeMove(board, line, myScore, oppScore)) {
        safeMoves.add(line);
      }
    }

    if (safeMoves.isNotEmpty) {
      if (beSmart) {
        return safeMoves[random.nextInt(safeMoves.length)];
      } else {
        if (random.nextDouble() < 0.5) {
          return safeMoves[random.nextInt(safeMoves.length)];
        }
      }
    }

    // --- REGOLA 3: Scegliere il male minore ---
    if (beSmart) {
      List<Line> riskyButNotTerrible = availableLines.where((l) => !badClosingMoves.contains(l) && !goodClosingMoves.contains(l)).toList();
      if (riskyButNotTerrible.isNotEmpty) {
        return riskyButNotTerrible[random.nextInt(riskyButNotTerrible.length)];
      }
    }

    List<Line> nonTerribleMoves = availableLines.where((l) => !badClosingMoves.contains(l)).toList();
    if (nonTerribleMoves.isNotEmpty) {
      return nonTerribleMoves[random.nextInt(nonTerribleMoves.length)];
    }

    return availableLines[random.nextInt(availableLines.length)];
  }

  static _ClosureResult _checkClosure(GameBoard board, Line line) {
    int netValue = 0;
    bool closesSomething = false;
    bool causesSwap = false;

    for (var box in board.boxes) {
      if (box.type == BoxType.invisible) continue;

      if (box.top == line || box.bottom == line || box.left == line || box.right == line) {
        int linesCount = 0;
        if (box.top.owner != Player.none || box.top == line) linesCount++;
        if (box.bottom.owner != Player.none || box.bottom == line) linesCount++;
        if (box.left.owner != Player.none || box.left == line) linesCount++;
        if (box.right.owner != Player.none || box.right == line) linesCount++;

        if (linesCount == 4) {
          closesSomething = true;

          // FIX: Togliamo la "vista a raggi X" all'Intelligenza Artificiale!
          if (box.hiddenJokerOwner == board.currentPlayer) {
            // L'IA conosce il suo Jolly, sa che vale +2 e cercherà di chiuderlo
            netValue += 2;
          } else {
            // Se c'è il Jolly del giocatore, l'IA NON DEVE SAPERLO e valuta la casella normalmente!
            if (box.type == BoxType.gold) netValue += 2;
            else if (box.type == BoxType.bomb) netValue -= 1;
            else if (box.type == BoxType.swap) netValue += 0;
            else netValue += 1;
          }

          if (box.type == BoxType.swap) causesSwap = true;
        }
      }
    }
    return _ClosureResult(closesSomething, netValue, causesSwap);
  }

  static bool _isSafeMove(GameBoard board, Line line, int myScore, int oppScore) {
    for (var box in board.boxes) {
      if (box.type == BoxType.invisible) continue;

      if (box.top == line || box.bottom == line || box.left == line || box.right == line) {
        int currentLinesCount = 0;
        if (box.top.owner != Player.none) currentLinesCount++;
        if (box.bottom.owner != Player.none) currentLinesCount++;
        if (box.left.owner != Player.none) currentLinesCount++;
        if (box.right.owner != Player.none) currentLinesCount++;

        if (currentLinesCount == 2) {

          // Nuova logica di sicurezza: cosa succede se l'IA lascia questa scatola all'avversario?
          int valueForOpponent = 0;
          if (box.hiddenJokerOwner == board.currentPlayer) {
            // Se l'avversario la chiude, becca la trappola dell'IA (-1).
            // Quindi PER L'IA È SICURISSIMO LASCIARE QUESTA CASELLA APERTA!
            valueForOpponent = -1;
          } else {
            if (box.type == BoxType.gold) valueForOpponent = 2;
            else if (box.type == BoxType.bomb) valueForOpponent = -1;
            else if (box.type == BoxType.swap) valueForOpponent = 0;
            else valueForOpponent = 1;
          }

          // Se per l'avversario vale -1 (bomba normale o trappola dell'IA), lasciamogliela!
          if (valueForOpponent < 0) {
            continue;
          }

          if (box.type == BoxType.swap) {
            if (myScore < oppScore) {
              continue;
            } else {
              return false;
            }
          }

          return false;
        }
      }
    }
    return true;
  }
}