import 'package:flutter/material.dart'; import 'package:playmaker/classe/home.config.dart'; import 'package:playmaker/grafico%20de%20pizza/grafico.dart'; import 'package:playmaker/pages/gamePage.dart'; import 'package:playmaker/pages/teamPage.dart'; import 'package:playmaker/controllers/team_controller.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:playmaker/pages/status_page.dart'; import 'dart:math' as math; import 'package:playmaker/grafico%20de%20pizza/controllers/contollers_grafico.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { int _selectedIndex = 0; final TeamController _teamController = TeamController(); String? _selectedTeamId; String _selectedTeamName = "Selecionar Equipa"; int _teamWins = 0; int _teamLosses = 0; int _teamDraws = 0; final _supabase = Supabase.instance.client; @override Widget build(BuildContext context) { final double wScreen = MediaQuery.of(context).size.width; final double hScreen = MediaQuery.of(context).size.height; final double sf = math.min(wScreen, hScreen) / 400; final List pages = [ _buildHomeContent(sf, wScreen), const GamePage(), const TeamsPage(), const StatusPage(), ]; return Scaffold( backgroundColor: Colors.white, appBar: AppBar( title: Text('PlayMaker', style: TextStyle(fontSize: 20 * sf)), backgroundColor: HomeConfig.primaryColor, foregroundColor: Colors.white, leading: IconButton( icon: Icon(Icons.person, size: 24 * sf), onPressed: () {}, ), ), body: IndexedStack( index: _selectedIndex, children: pages, ), bottomNavigationBar: NavigationBar( selectedIndex: _selectedIndex, onDestinationSelected: (index) => setState(() => _selectedIndex = index), backgroundColor: Theme.of(context).colorScheme.surface, surfaceTintColor: Theme.of(context).colorScheme.surfaceTint, elevation: 1, height: 70 * math.min(sf, 1.2), destinations: const [ NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home_filled), label: 'Home'), NavigationDestination(icon: Icon(Icons.sports_soccer_outlined), selectedIcon: Icon(Icons.sports_soccer), label: 'Jogo'), NavigationDestination(icon: Icon(Icons.people_outline), selectedIcon: Icon(Icons.people), label: 'Equipas'), NavigationDestination(icon: Icon(Icons.insights_outlined), selectedIcon: Icon(Icons.insights), label: 'Status'), ], ), ); } void _showTeamSelector(BuildContext context, double sf) { showModalBottomSheet( context: context, shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(20 * sf))), builder: (context) { return StreamBuilder>>( stream: _teamController.teamsStream, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) return const SizedBox(height: 200, child: Center(child: CircularProgressIndicator())); if (!snapshot.hasData || snapshot.data!.isEmpty) return SizedBox(height: 200 * sf, child: const Center(child: Text("Nenhuma equipa criada."))); final teams = snapshot.data!; return ListView.builder( shrinkWrap: true, itemCount: teams.length, itemBuilder: (context, index) { final team = teams[index]; return ListTile( title: Text(team['name']), onTap: () { setState(() { _selectedTeamId = team['id']; _selectedTeamName = team['name']; _teamWins = team['wins'] != null ? int.tryParse(team['wins'].toString()) ?? 0 : 0; _teamLosses = team['losses'] != null ? int.tryParse(team['losses'].toString()) ?? 0 : 0; _teamDraws = team['draws'] != null ? int.tryParse(team['draws'].toString()) ?? 0 : 0; }); Navigator.pop(context); }, ); }, ); }, ); }, ); } Widget _buildHomeContent(double sf, double wScreen) { final double cardHeight = (wScreen / 2) * 1.0; return StreamBuilder>>( stream: _selectedTeamId != null ? _supabase.from('player_stats_with_names').stream(primaryKey: ['id']).eq('team_id', _selectedTeamId!) : const Stream.empty(), builder: (context, snapshot) { Map leaders = _calculateLeaders(snapshot.data ?? []); return SingleChildScrollView( child: Padding( padding: EdgeInsets.symmetric(horizontal: 22.0 * sf, vertical: 16.0 * sf), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ InkWell( onTap: () => _showTeamSelector(context, sf), child: Container( padding: EdgeInsets.all(12 * sf), decoration: BoxDecoration(color: Colors.grey.shade100, borderRadius: BorderRadius.circular(15 * sf), border: Border.all(color: Colors.grey.shade300)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row(children: [Icon(Icons.shield, color: HomeConfig.primaryColor, size: 24 * sf), SizedBox(width: 10 * sf), Text(_selectedTeamName, style: TextStyle(fontSize: 16 * sf, fontWeight: FontWeight.bold))]), const Icon(Icons.arrow_drop_down), ], ), ), ), SizedBox(height: 20 * sf), SizedBox( height: cardHeight, child: Row( children: [ Expanded(child: _buildStatCard(title: 'Mais Pontos', playerName: leaders['pts_name'], statValue: leaders['pts_val'].toString(), statLabel: 'TOTAL', color: const Color(0xFF1565C0), isHighlighted: true)), SizedBox(width: 12 * sf), Expanded(child: _buildStatCard(title: 'Assistências', playerName: leaders['ast_name'], statValue: leaders['ast_val'].toString(), statLabel: 'TOTAL', color: const Color(0xFF2E7D32))), ], ), ), SizedBox(height: 12 * sf), SizedBox( height: cardHeight, child: Row( children: [ Expanded(child: _buildStatCard(title: 'Rebotes', playerName: leaders['rbs_name'], statValue: leaders['rbs_val'].toString(), statLabel: 'TOTAL', color: const Color(0xFF6A1B9A))), SizedBox(width: 12 * sf), Expanded( child: PieChartCard( victories: _teamWins, defeats: _teamLosses, draws: _teamDraws, title: 'DESEMPENHO', subtitle: 'Temporada', backgroundColor: const Color(0xFFC62828), sf: sf ), ), ], ), ), SizedBox(height: 40 * sf), Text('Histórico de Jogos', style: TextStyle(fontSize: 20 * sf, fontWeight: FontWeight.bold, color: Colors.grey[800])), SizedBox(height: 16 * sf), // 👇 HISTÓRICO LIGADO À BASE DE DADOS (COM AS COLUNAS CORRIGIDAS) 👇 // 👇 LIGAÇÃO CORRIGIDA: Agora usa a coluna 'nome' como pediste 👇 // 👇 HISTÓRICO DINÂMICO (Qualquer equipa) 👇 _selectedTeamName == "Selecionar Equipa" ? Container( padding: EdgeInsets.all(20 * sf), alignment: Alignment.center, child: Text("Seleciona uma equipa no topo.", style: TextStyle(color: Colors.grey, fontSize: 14 * sf)), ) : StreamBuilder>>( // Pede os jogos ordenados pela data (sem filtros rígidos aqui) stream: _supabase.from('games').stream(primaryKey: ['id']) .order('game_date', ascending: false), builder: (context, gameSnapshot) { if (gameSnapshot.hasError) { return Text("Erro ao carregar jogos: ${gameSnapshot.error}", style: const TextStyle(color: Colors.red)); } if (gameSnapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // 👇 O CÉREBRO DA APP: Filtro inteligente no Flutter 👇 final todosOsJogos = gameSnapshot.data ?? []; final gamesList = todosOsJogos.where((game) { String myT = game['my_team']?.toString() ?? ''; String oppT = game['opponent_team']?.toString() ?? ''; String status = game['status']?.toString() ?? ''; // O jogo tem de envolver a equipa selecionada E estar Terminado bool isPlaying = (myT == _selectedTeamName || oppT == _selectedTeamName); bool isFinished = status == 'Terminado'; return isPlaying && isFinished; }).take(3).toList(); // Pega apenas nos 3 mais recentes if (gamesList.isEmpty) { return Container( padding: EdgeInsets.all(20 * sf), decoration: BoxDecoration(color: Colors.grey.shade50, borderRadius: BorderRadius.circular(14)), alignment: Alignment.center, child: Text("Ainda não há jogos terminados para $_selectedTeamName.", style: TextStyle(color: Colors.grey)), ); } return Column( children: gamesList.map((game) { // Lê os dados brutos da base de dados String dbMyTeam = game['my_team']?.toString() ?? ''; String dbOppTeam = game['opponent_team']?.toString() ?? ''; int dbMyScore = int.tryParse(game['my_score'].toString()) ?? 0; int dbOppScore = int.tryParse(game['opponent_score'].toString()) ?? 0; String opponent; int myScore; int oppScore; // 🔄 MAGIA DA INVERSÃO DE RESULTADOS 🔄 // Garante que os pontos da equipa selecionada aparecem sempre do lado esquerdo if (dbMyTeam == _selectedTeamName) { // A equipa que escolhemos está guardada no 'my_team' opponent = dbOppTeam; myScore = dbMyScore; oppScore = dbOppScore; } else { // A equipa que escolhemos está guardada no 'opponent_team' opponent = dbMyTeam; myScore = dbOppScore; oppScore = dbMyScore; } // Limpa a data (Remove as horas e deixa só YYYY-MM-DD) String rawDate = game['game_date']?.toString() ?? '---'; String date = rawDate.length >= 10 ? rawDate.substring(0, 10) : rawDate; // Calcula Vitória, Empate ou Derrota para a equipa selecionada String result = 'E'; if (myScore > oppScore) result = 'V'; if (myScore < oppScore) result = 'D'; return _buildGameHistoryCard( opponent: opponent, result: result, myScore: myScore, oppScore: oppScore, date: date, sf: sf, topPts: game['top_pts_name'] ?? '---', topAst: game['top_ast_name'] ?? '---', topRbs: game['top_rbs_name'] ?? '---', topDef: game['top_def_name'] ?? '---', mvp: game['mvp_name'] ?? '---', ); }).toList(), ); }, ), SizedBox(height: 20 * sf), ], ), ), ); }, ); } Map _calculateLeaders(List> data) { Map ptsMap = {}; Map astMap = {}; Map rbsMap = {}; Map namesMap = {}; for (var row in data) { String pid = row['member_id'].toString(); namesMap[pid] = row['player_name']?.toString() ?? "Desconhecido"; ptsMap[pid] = (ptsMap[pid] ?? 0) + (row['pts'] as int? ?? 0); astMap[pid] = (astMap[pid] ?? 0) + (row['ast'] as int? ?? 0); rbsMap[pid] = (rbsMap[pid] ?? 0) + (row['rbs'] as int? ?? 0); } if (ptsMap.isEmpty) return {'pts_name': '---', 'pts_val': 0, 'ast_name': '---', 'ast_val': 0, 'rbs_name': '---', 'rbs_val': 0}; String getBest(Map map) { var bestId = map.entries.reduce((a, b) => a.value > b.value ? a : b).key; return namesMap[bestId]!; } int getBestVal(Map map) => map.values.reduce((a, b) => a > b ? a : b); return {'pts_name': getBest(ptsMap), 'pts_val': getBestVal(ptsMap), 'ast_name': getBest(astMap), 'ast_val': getBestVal(astMap), 'rbs_name': getBest(rbsMap), 'rbs_val': getBestVal(rbsMap)}; } Widget _buildStatCard({required String title, required String playerName, required String statValue, required String statLabel, required Color color, bool isHighlighted = false}) { return Card( elevation: 4, margin: EdgeInsets.zero, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14), side: isHighlighted ? const BorderSide(color: Colors.amber, width: 2) : BorderSide.none), child: Container( decoration: BoxDecoration(borderRadius: BorderRadius.circular(14), gradient: LinearGradient(begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [color.withOpacity(0.9), color])), child: LayoutBuilder( builder: (context, constraints) { final double ch = constraints.maxHeight; final double cw = constraints.maxWidth; return Padding( padding: EdgeInsets.all(cw * 0.06), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title.toUpperCase(), style: TextStyle(fontSize: ch * 0.06, fontWeight: FontWeight.bold, color: Colors.white70), maxLines: 1, overflow: TextOverflow.ellipsis), SizedBox(height: ch * 0.011), SizedBox( width: double.infinity, child: FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.centerLeft, child: Text(playerName, style: TextStyle(fontSize: ch * 0.08, fontWeight: FontWeight.bold, color: Colors.white)), ), ), const Spacer(), Center(child: FittedBox(fit: BoxFit.scaleDown, child: Text(statValue, style: TextStyle(fontSize: ch * 0.18, fontWeight: FontWeight.bold, color: Colors.white, height: 1.0)))), SizedBox(height: ch * 0.015), Center(child: Text(statLabel, style: TextStyle(fontSize: ch * 0.05, color: Colors.white70))), const Spacer(), Container( width: double.infinity, padding: EdgeInsets.symmetric(vertical: ch * 0.035), decoration: BoxDecoration(color: Colors.white24, borderRadius: BorderRadius.circular(ch * 0.03)), child: Center(child: Text('DETALHES', style: TextStyle(color: Colors.white, fontSize: ch * 0.05, fontWeight: FontWeight.bold))) ), ], ), ); } ), ), ); } Widget _buildGameHistoryCard({ required String opponent, required String result, required int myScore, required int oppScore, required String date, required double sf, required String topPts, required String topAst, required String topRbs, required String topDef, required String mvp }) { bool isWin = result == 'V'; bool isDraw = result == 'E'; Color statusColor = isWin ? Colors.green : (isDraw ? Colors.yellow.shade700 : Colors.red); return Container( margin: EdgeInsets.only(bottom: 14 * sf), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all(color: Colors.grey.shade200), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.04), blurRadius: 8, offset: const Offset(0, 4))], ), child: Column( children: [ Padding( padding: EdgeInsets.all(14 * sf), child: Row( children: [ Container( width: 36 * sf, height: 36 * sf, decoration: BoxDecoration(color: statusColor.withOpacity(0.15), shape: BoxShape.circle), child: Center(child: Text(result, style: TextStyle(color: statusColor, fontWeight: FontWeight.bold, fontSize: 16 * sf))), ), SizedBox(width: 14 * sf), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(date, style: TextStyle(fontSize: 11 * sf, color: Colors.grey, fontWeight: FontWeight.w600)), SizedBox(height: 6 * sf), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(child: Text(_selectedTeamName == "Selecionar Equipa" ? "Minha Equipa" : _selectedTeamName, style: TextStyle(fontSize: 14 * sf, fontWeight: FontWeight.bold), maxLines: 1, overflow: TextOverflow.ellipsis)), Padding( padding: EdgeInsets.symmetric(horizontal: 8 * sf), child: Container( padding: EdgeInsets.symmetric(horizontal: 8 * sf, vertical: 4 * sf), decoration: BoxDecoration(color: Colors.grey.shade100, borderRadius: BorderRadius.circular(8)), child: Text('$myScore - $oppScore', style: TextStyle(fontSize: 15 * sf, fontWeight: FontWeight.w900, letterSpacing: 1.5, color: Colors.black87)), ), ), Expanded(child: Text(opponent, style: TextStyle(fontSize: 14 * sf, fontWeight: FontWeight.bold), textAlign: TextAlign.right, maxLines: 1, overflow: TextOverflow.ellipsis)), ], ), ], ), ), ], ), ), Divider(height: 1, color: Colors.grey.shade100, thickness: 1.5), Container( width: double.infinity, padding: EdgeInsets.symmetric(horizontal: 16 * sf, vertical: 12 * sf), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(16), bottomRight: Radius.circular(16)), ), child: Column( children: [ Row( children: [ Expanded(child: _buildGridStatRow(Icons.workspace_premium, Colors.amber.shade700, "MVP", mvp, sf, isMvp: true)), Expanded(child: _buildGridStatRow(Icons.shield, Colors.deepOrange.shade700, "Defesa", topDef, sf)), ], ), SizedBox(height: 8 * sf), Row( children: [ Expanded(child: _buildGridStatRow(Icons.bolt, Colors.blue.shade700, "Pontos", topPts, sf)), Expanded(child: _buildGridStatRow(Icons.trending_up, Colors.purple.shade700, "Rebotes", topRbs, sf)), ], ), SizedBox(height: 8 * sf), Row( children: [ Expanded(child: _buildGridStatRow(Icons.star, Colors.green.shade700, "Assists", topAst, sf)), const Expanded(child: SizedBox()), ], ), ], ), ) ], ), ); } Widget _buildGridStatRow(IconData icon, Color color, String label, String value, double sf, {bool isMvp = false}) { return Row( children: [ Icon(icon, size: 14 * sf, color: color), SizedBox(width: 4 * sf), Text('$label: ', style: TextStyle(fontSize: 11 * sf, color: Colors.grey.shade600, fontWeight: FontWeight.bold)), Expanded( child: Text( value, style: TextStyle( fontSize: 11 * sf, color: isMvp ? Colors.amber.shade900 : Colors.black87, fontWeight: FontWeight.bold ), maxLines: 1, overflow: TextOverflow.ellipsis ) ), ], ); } }