import 'dart:async';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

class ShotRecord {
  final double relativeX;
  final double relativeY;
  final bool isMake;
  final String playerName;

  ShotRecord({
    required this.relativeX, 
    required this.relativeY, 
    required this.isMake, 
    required this.playerName
  });
}

class PlacarController {
  final String gameId;
  final String myTeam;
  final String opponentTeam;
  final VoidCallback onUpdate;

  PlacarController({
    required this.gameId, 
    required this.myTeam, 
    required this.opponentTeam, 
    required this.onUpdate
  });

  bool isLoading = true;
  bool isSaving = false;
  bool gameWasAlreadyFinished = false; 

  int myScore = 0;
  int opponentScore = 0;
  int myFouls = 0;
  int opponentFouls = 0;
  int currentQuarter = 1;
  int myTimeoutsUsed = 0;
  int opponentTimeoutsUsed = 0;

  String? myTeamDbId;
  String? oppTeamDbId;

  List<String> myCourt = [];
  List<String> myBench = [];
  List<String> oppCourt = [];
  List<String> oppBench = [];

  Map<String, String> playerNumbers = {};
  Map<String, Map<String, int>> playerStats = {};
  Map<String, String> playerDbIds = {};

  bool showMyBench = false;
  bool showOppBench = false;

  bool isSelectingShotLocation = false;
  String? pendingAction;
  String? pendingPlayer;
  List<ShotRecord> matchShots = [];

  Duration duration = const Duration(minutes: 10);
  Timer? timer;
  bool isRunning = false;

  // OS TEUS NÚMEROS DE OURO DO TABLET
  bool isCalibrating = false; 
  double hoopBaseX = 0.000;    
  double arcRadius = 0.500;    
  double cornerY = 0.443;      

  Future<void> loadPlayers() async {
    final supabase = Supabase.instance.client;
    try {
      await Future.delayed(const Duration(milliseconds: 1500)); 

      myCourt.clear(); myBench.clear(); oppCourt.clear(); oppBench.clear();
      playerStats.clear(); playerNumbers.clear(); playerDbIds.clear();
      myFouls = 0; opponentFouls = 0;

      final gameResponse = await supabase.from('games').select().eq('id', gameId).single();
      
      myScore = int.tryParse(gameResponse['my_score']?.toString() ?? '0') ?? 0;
      opponentScore = int.tryParse(gameResponse['opponent_score']?.toString() ?? '0') ?? 0;
      int totalSeconds = int.tryParse(gameResponse['remaining_seconds']?.toString() ?? '600') ?? 600;
      duration = Duration(seconds: totalSeconds);
      myTimeoutsUsed = int.tryParse(gameResponse['my_timeouts']?.toString() ?? '0') ?? 0;
      opponentTimeoutsUsed = int.tryParse(gameResponse['opp_timeouts']?.toString() ?? '0') ?? 0;
      currentQuarter = int.tryParse(gameResponse['current_quarter']?.toString() ?? '1') ?? 1;
      
      gameWasAlreadyFinished = gameResponse['status'] == 'Terminado'; 

      final teamsResponse = await supabase.from('teams').select('id, name').inFilter('name', [myTeam, opponentTeam]);
      for (var t in teamsResponse) {
        if (t['name'] == myTeam) myTeamDbId = t['id'];
        if (t['name'] == opponentTeam) oppTeamDbId = t['id'];
      }

      List<dynamic> myPlayers = myTeamDbId != null ? await supabase.from('members').select().eq('team_id', myTeamDbId!).eq('type', 'Jogador') : [];
      List<dynamic> oppPlayers = oppTeamDbId != null ? await supabase.from('members').select().eq('team_id', oppTeamDbId!).eq('type', 'Jogador') : [];

      final statsResponse = await supabase.from('player_stats').select().eq('game_id', gameId);
      final Map<String, dynamic> savedStats = {
        for (var item in statsResponse) item['member_id'].toString(): item
      };

      for (int i = 0; i < myPlayers.length; i++) {
        String dbId = myPlayers[i]['id'].toString();
        String name = myPlayers[i]['name'].toString();
        _registerPlayer(name: name, number: myPlayers[i]['number']?.toString() ?? "0", dbId: dbId, isMyTeam: true, isCourt: i < 5);
        if (savedStats.containsKey(dbId)) {
          var s = savedStats[dbId];
          playerStats[name] = { "pts": s['pts'] ?? 0, "rbs": s['rbs'] ?? 0, "ast": s['ast'] ?? 0, "stl": s['stl'] ?? 0, "tov": s['tov'] ?? 0, "blk": s['blk'] ?? 0, "fls": s['fls'] ?? 0, "fgm": s['fgm'] ?? 0, "fga": s['fga'] ?? 0, "ftm": s['ftm'] ?? 0, "fta": s['fta'] ?? 0, "orb": s['orb'] ?? 0, "drb": s['drb'] ?? 0 };
          myFouls += (s['fls'] as int? ?? 0); 
        }
      }
      _padTeam(myCourt, myBench, "Jogador", isMyTeam: true);

      for (int i = 0; i < oppPlayers.length; i++) {
        String dbId = oppPlayers[i]['id'].toString();
        String name = oppPlayers[i]['name'].toString();
        _registerPlayer(name: name, number: oppPlayers[i]['number']?.toString() ?? "0", dbId: dbId, isMyTeam: false, isCourt: i < 5);
        if (savedStats.containsKey(dbId)) {
          var s = savedStats[dbId];
          playerStats[name] = { "pts": s['pts'] ?? 0, "rbs": s['rbs'] ?? 0, "ast": s['ast'] ?? 0, "stl": s['stl'] ?? 0, "tov": s['tov'] ?? 0, "blk": s['blk'] ?? 0, "fls": s['fls'] ?? 0, "fgm": s['fgm'] ?? 0, "fga": s['fga'] ?? 0, "ftm": s['ftm'] ?? 0, "fta": s['fta'] ?? 0, "orb": s['orb'] ?? 0, "drb": s['drb'] ?? 0 };
          opponentFouls += (s['fls'] as int? ?? 0);
        }
      }
      _padTeam(oppCourt, oppBench, "Adversário", isMyTeam: false);

      // Carregar Shots salvos para o HeatMap
      final shotsResponse = await supabase.from('game_shots').select().eq('game_id', gameId);
      matchShots = (shotsResponse as List).map((s) => ShotRecord(
        relativeX: (s['relative_x'] as num).toDouble(),
        relativeY: (s['relative_y'] as num).toDouble(),
        isMake: s['is_make'] as bool,
        playerName: s['player_name'],
      )).toList();

      isLoading = false;
      onUpdate();
    } catch (e) {
      debugPrint("Erro ao retomar jogo: $e");
      isLoading = false;
      onUpdate();
    }
  }

  void _registerPlayer({required String name, required String number, String? dbId, required bool isMyTeam, required bool isCourt}) {
    if (playerNumbers.containsKey(name)) name = "$name (Opp)"; 
    playerNumbers[name] = number;
    if (dbId != null) playerDbIds[name] = dbId; 
    playerStats[name] = { "pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0, "fls": 0, "fgm": 0, "fga": 0, "ftm": 0, "fta": 0, "orb": 0, "drb": 0 };
    if (isMyTeam) { if (isCourt) myCourt.add(name); else myBench.add(name); } 
    else { if (isCourt) oppCourt.add(name); else oppBench.add(name); }
  }

  void _padTeam(List<String> court, List<String> bench, String prefix, {required bool isMyTeam}) {
    while (court.length < 5) {
      _registerPlayer(name: "Sem $prefix ${court.length + 1}", number: "0", dbId: null, isMyTeam: isMyTeam, isCourt: true);
    }
  }

  void toggleTimer(BuildContext context) {
    if (isRunning) {
      timer?.cancel();
    } else {
      timer = Timer.periodic(const Duration(seconds: 1), (timer) {
        if (duration.inSeconds > 0) {
          duration -= const Duration(seconds: 1);
        } else {
          timer.cancel();
          isRunning = false;
          if (currentQuarter < 4) {
            currentQuarter++; 
            duration = const Duration(minutes: 10); 
            myFouls = 0; opponentFouls = 0; myTimeoutsUsed = 0; opponentTimeoutsUsed = 0; 
            onUpdate();
          }
        }
        onUpdate();
      });
    }
    isRunning = !isRunning;
    onUpdate();
  }

  void useTimeout(bool isOpponent) {
    if (isOpponent) { if (opponentTimeoutsUsed < 3) opponentTimeoutsUsed++; } 
    else { if (myTimeoutsUsed < 3) myTimeoutsUsed++; }
    isRunning = false;
    timer?.cancel();
    onUpdate();
  }

  String formatTime() => "${duration.inMinutes.toString().padLeft(2, '0')}:${duration.inSeconds.remainder(60).toString().padLeft(2, '0')}";

  void handleActionDrag(BuildContext context, String action, String playerData) {
    String name = playerData.replaceAll("player_my_", "").replaceAll("player_opp_", "");
    final stats = playerStats[name]!;

    if (stats["fls"]! >= 5 && action != "sub_foul") {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('🛑 $name atingiu 5 faltas e está expulso!'), backgroundColor: Colors.red));
      return;
    }

    if (action == "add_pts_2" || action == "add_pts_3" || action == "miss_2" || action == "miss_3") {
      pendingAction = action;
      pendingPlayer = playerData;
      isSelectingShotLocation = true;
    } else {
      commitStat(action, playerData);
    }
    onUpdate();
  }

  void handleSubbing(BuildContext context, String action, String courtPlayerName, bool isOpponent) {
    if (action.startsWith("bench_my_") && !isOpponent) {
      String benchPlayer = action.replaceAll("bench_my_", "");
      if (playerStats[benchPlayer]!["fls"]! >= 5) return; 
      int courtIndex = myCourt.indexOf(courtPlayerName);
      int benchIndex = myBench.indexOf(benchPlayer);
      myCourt[courtIndex] = benchPlayer;
      myBench[benchIndex] = courtPlayerName;
      showMyBench = false;
    }
    if (action.startsWith("bench_opp_") && isOpponent) {
      String benchPlayer = action.replaceAll("bench_opp_", "");
      if (playerStats[benchPlayer]!["fls"]! >= 5) return;
      int courtIndex = oppCourt.indexOf(courtPlayerName);
      int benchIndex = oppBench.indexOf(benchPlayer);
      oppCourt[courtIndex] = benchPlayer;
      oppBench[benchIndex] = courtPlayerName;
      showOppBench = false;
    }
    onUpdate();
  }

  // ==============================================================
  // 🎯 REGISTO DO TOQUE (INTELIGENTE E SILENCIOSO)
  // ==============================================================
  void registerShotLocation(BuildContext context, Offset position, Size size) {
    if (pendingAction == null || pendingPlayer == null) return;
    
    bool isOpponent = pendingPlayer!.startsWith("player_opp_");
    bool is3Pt = pendingAction!.contains("_3");
    bool is2Pt = pendingAction!.contains("_2");

    if (is3Pt || is2Pt) {
      bool isInside2Pts = _validateShotZone(position, size, isOpponent);
      
      // Bloqueio silencioso (sem notificações chamas)
      if ((is2Pt && !isInside2Pts) || (is3Pt && isInside2Pts)) {
        cancelShotLocation(); 
        return; 
      }
    }

    bool isMake = pendingAction!.startsWith("add_pts_");
    double relX = position.dx / size.width;
    double relY = position.dy / size.height;
    String name = pendingPlayer!.replaceAll("player_my_", "").replaceAll("player_opp_", "");

    matchShots.add(ShotRecord(relativeX: relX, relativeY: relY, isMake: isMake, playerName: name));
    commitStat(pendingAction!, pendingPlayer!);
    
    isSelectingShotLocation = false;
    pendingAction = null;
    pendingPlayer = null;
    onUpdate();
  }

  // ==============================================================
  // 📐 MATEMÁTICA PURA: LÓGICA DE MEIO-CAMPO ATACANTE (SOLUÇÃO DIVIDIDA)
  // ==============================================================
  bool _validateShotZone(Offset position, Size size, bool isOpponent) {
    double relX = position.dx / size.width;
    double relY = position.dy / size.height;

    double hX = hoopBaseX;
    double radius = arcRadius;
    double cY = cornerY;

    // A Minha Equipa defende na Esquerda (0.0), logo ataca o cesto da Direita (1.0)
    // O Adversário defende na Direita (1.0), logo ataca o cesto da Esquerda (0.0)
    double hoopX = isOpponent ? hX : (1.0 - hX);
    double hoopY = 0.50; 

    double aspectRatio = size.width / size.height;
    double distFromCenterY = (relY - hoopY).abs(); 

    // Descobre se o toque foi feito na metade atacante daquela equipa
    bool isAttackingHalf = isOpponent ? (relX < 0.5) : (relX > 0.5);

    if (isAttackingHalf && distFromCenterY > cY) {
      return false; // É 3 pontos (Zona dos Cantos)
    } else {
      double dx = (relX - hoopX) * aspectRatio;
      double dy = (relY - hoopY);
      double distanceToHoop = math.sqrt((dx * dx) + (dy * dy));
      return distanceToHoop <= radius;
    }
  }

  void cancelShotLocation() {
    isSelectingShotLocation = false; pendingAction = null; pendingPlayer = null; onUpdate();
  }

  void commitStat(String action, String playerData) {
    bool isOpponent = playerData.startsWith("player_opp_");
    String name = playerData.replaceAll("player_my_", "").replaceAll("player_opp_", "");
    final stats = playerStats[name]!;

    if (action.startsWith("add_pts_")) {
      int pts = int.parse(action.split("_").last);
      if (isOpponent) opponentScore += pts; else myScore += pts;
      stats["pts"] = stats["pts"]! + pts;
      if (pts == 2 || pts == 3) { stats["fgm"] = stats["fgm"]! + 1; stats["fga"] = stats["fga"]! + 1; }
      if (pts == 1) { stats["ftm"] = stats["ftm"]! + 1; stats["fta"] = stats["fta"]! + 1; } 
    } 
    else if (action.startsWith("sub_pts_")) {
      int pts = int.parse(action.split("_").last);
      if (isOpponent) { opponentScore = (opponentScore - pts < 0) ? 0 : opponentScore - pts; } 
      else { myScore = (myScore - pts < 0) ? 0 : myScore - pts; }
      stats["pts"] = (stats["pts"]! - pts < 0) ? 0 : stats["pts"]! - pts;
      if (pts == 2 || pts == 3) {
        if (stats["fgm"]! > 0) stats["fgm"] = stats["fgm"]! - 1;
        if (stats["fga"]! > 0) stats["fga"] = stats["fga"]! - 1;
      }
      if (pts == 1) { 
        if (stats["ftm"]! > 0) stats["ftm"] = stats["ftm"]! - 1;
        if (stats["fta"]! > 0) stats["fta"] = stats["fta"]! - 1;
      }
    } 
    else if (action == "miss_1") { stats["fta"] = stats["fta"]! + 1; } 
    else if (action == "miss_2" || action == "miss_3") { stats["fga"] = stats["fga"]! + 1; }
    else if (action == "add_orb") { stats["orb"] = stats["orb"]! + 1; stats["rbs"] = stats["rbs"]! + 1; } 
    else if (action == "add_drb") { stats["drb"] = stats["drb"]! + 1; stats["rbs"] = stats["rbs"]! + 1; } 
    else if (action == "add_ast") { stats["ast"] = stats["ast"]! + 1; }
    else if (action == "add_stl") { stats["stl"] = stats["stl"]! + 1; }
    else if (action == "add_tov") { stats["tov"] = stats["tov"]! + 1; }
    else if (action == "add_blk") { stats["blk"] = stats["blk"]! + 1; }
    else if (action == "add_foul") { 
      stats["fls"] = stats["fls"]! + 1; 
      if (isOpponent) { opponentFouls++; } else { myFouls++; }
    }
    else if (action == "sub_foul") {
      if (stats["fls"]! > 0) stats["fls"] = stats["fls"]! - 1;
      if (isOpponent) { if (opponentFouls > 0) opponentFouls--; } else { if (myFouls > 0) myFouls--; }
    }
  }

  Future<void> saveGameStats(BuildContext context) async {
    final supabase = Supabase.instance.client;
    isSaving = true;
    onUpdate();

    try {
      bool isGameFinishedNow = (currentQuarter >= 4 && duration.inSeconds == 0);
      String newStatus = isGameFinishedNow ? 'Terminado' : 'Pausado';

      String topPtsName = '---'; int maxPts = -1;
      String topAstName = '---'; int maxAst = -1;
      String topRbsName = '---'; int maxRbs = -1;
      String topDefName = '---'; int maxDef = -1;
      String mvpName = '---';    int maxMvpScore = -1;

      playerStats.forEach((playerName, stats) {
        int pts = stats['pts'] ?? 0;
        int ast = stats['ast'] ?? 0;
        int rbs = stats['rbs'] ?? 0;
        int stl = stats['stl'] ?? 0;
        int blk = stats['blk'] ?? 0;
        int defScore = stl + blk; 
        int mvpScore = pts + ast + rbs + defScore; 
        if (pts > maxPts && pts > 0) { maxPts = pts; topPtsName = '$playerName ($pts)'; }
        if (ast > maxAst && ast > 0) { maxAst = ast; topAstName = '$playerName ($ast)'; }
        if (rbs > maxRbs && rbs > 0) { maxRbs = rbs; topRbsName = '$playerName ($rbs)'; }
        if (defScore > maxDef && defScore > 0) { maxDef = defScore; topDefName = '$playerName ($defScore)'; }
        if (mvpScore > maxMvpScore && mvpScore > 0) { maxMvpScore = mvpScore; mvpName = playerName; } 
      });

      await supabase.from('games').update({
        'my_score': myScore, 'opponent_score': opponentScore, 'remaining_seconds': duration.inSeconds,
        'my_timeouts': myTimeoutsUsed, 'opp_timeouts': opponentTimeoutsUsed, 'current_quarter': currentQuarter,
        'status': newStatus, 'top_pts_name': topPtsName, 'top_ast_name': topAstName, 'top_rbs_name': topRbsName,
        'top_def_name': topDefName, 'mvp_name': mvpName,
      }).eq('id', gameId);

      // Atualiza Vitórias/Derrotas se o jogo terminou
      if (isGameFinishedNow && !gameWasAlreadyFinished && myTeamDbId != null && oppTeamDbId != null) {
        final teamsData = await supabase.from('teams').select('id, wins, losses, draws').inFilter('id', [myTeamDbId, oppTeamDbId]);
        for(var t in teamsData) {
          if(t['id'].toString() == myTeamDbId) {
             int w = (t['wins'] ?? 0) + (myScore > opponentScore ? 1 : 0);
             int l = (t['losses'] ?? 0) + (myScore < opponentScore ? 1 : 0);
             int d = (t['draws'] ?? 0) + (myScore == opponentScore ? 1 : 0);
             await supabase.from('teams').update({'wins': w, 'losses': l, 'draws': d}).eq('id', myTeamDbId!);
          } else {
             int w = (t['wins'] ?? 0) + (opponentScore > myScore ? 1 : 0);
             int l = (t['losses'] ?? 0) + (opponentScore < myScore ? 1 : 0);
             int d = (t['draws'] ?? 0) + (opponentScore == myScore ? 1 : 0);
             await supabase.from('teams').update({'wins': w, 'losses': l, 'draws': d}).eq('id', oppTeamDbId!);
          }
        }
        gameWasAlreadyFinished = true;
      }

      // Salvar Estatísticas Gerais
      List<Map<String, dynamic>> batchStats = [];
      playerStats.forEach((playerName, stats) {
        String? memberDbId = playerDbIds[playerName]; 
        if (memberDbId != null && stats.values.any((val) => val > 0)) {
          bool isMyTeamPlayer = myCourt.contains(playerName) || myBench.contains(playerName);
          batchStats.add({
            'game_id': gameId, 'member_id': memberDbId, 'team_id': isMyTeamPlayer ? myTeamDbId! : oppTeamDbId!,
            'pts': stats['pts'], 'rbs': stats['rbs'], 'ast': stats['ast'], 'stl': stats['stl'], 'blk': stats['blk'], 'tov': stats['tov'], 'fls': stats['fls'], 'fgm': stats['fgm'], 'fga': stats['fga'], 'ftm': stats['ftm'], 'fta': stats['fta'], 'orb': stats['orb'], 'drb': stats['drb'],
          });
        }
      });
      await supabase.from('player_stats').delete().eq('game_id', gameId);
      if (batchStats.isNotEmpty) await supabase.from('player_stats').insert(batchStats);

      // ===============================================
      // 🔥 GRAVAR COORDENADAS PARA O HEATMAP
      // ===============================================
      List<Map<String, dynamic>> shotsData = [];
      for (var shot in matchShots) {
        bool isMyTeamPlayer = myCourt.contains(shot.playerName) || myBench.contains(shot.playerName);
        shotsData.add({
          'game_id': gameId,
          'team_id': isMyTeamPlayer ? myTeamDbId! : oppTeamDbId!,
          'player_name': shot.playerName,
          'relative_x': shot.relativeX,
          'relative_y': shot.relativeY,
          'is_make': shot.isMake,
        });
      }
      await supabase.from('game_shots').delete().eq('game_id', gameId);
      if (shotsData.isNotEmpty) await supabase.from('game_shots').insert(shotsData);

      if (context.mounted) {
        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Tudo guardado com Sucesso!'), backgroundColor: Colors.green));
      }
    } catch (e) {
      if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Erro ao guardar: $e'), backgroundColor: Colors.red));
    } finally {
      isSaving = false;
      onUpdate();
    }
  }

  void dispose() {
    timer?.cancel();
  }
} 