import 'dart:math' as math;
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

// Modelo local para os tiros
class _ShotDot {
  final double relX;
  final double relY;
  final bool isMake;
  _ShotDot({required this.relX, required this.relY, required this.isMake});
}

class PdfExportService {
  // ════════════════════════════════════════════════════════════════════════════
  // ENTRY POINT
  // ════════════════════════════════════════════════════════════════════════════

  static Future<void> generateAndPrintBoxScore({
    required String gameId,
    required String myTeam,
    required String opponentTeam,
    required String myScore,
    required String opponentScore,
    required String season,
  }) async {
    final supabase = Supabase.instance.client;

    // ── Jogo ────────────────────────────────────────────────────────────────
    final gameData =
        await supabase.from('games').select().eq('id', gameId).single();

    // ── Equipas ─────────────────────────────────────────────────────────────
    final teamsData = await supabase
        .from('teams')
        .select('id, name')
        .inFilter('name', [myTeam, opponentTeam]);

    String? myTeamId;
    for (var t in teamsData) {
      if (t['name'] == myTeam) myTeamId = t['id'].toString();
    }

    // ── Jogadores (Apenas a minha equipa) ───────────────────────────────────
    List<dynamic> myPlayers = myTeamId != null
        ? await supabase
            .from('members')
            .select()
            .eq('team_id', myTeamId)
            .eq('type', 'Jogador')
        : [];

    // ── Estatísticas ─────────────────────────────────────────────────────────
    final statsData =
        await supabase.from('player_stats').select().eq('game_id', gameId);
    Map<String, Map<String, dynamic>> statsMap = {};
    for (var s in statsData) {
      statsMap[s['member_id'].toString()] = s;
    }

    // ── Tiros (para o mapa de calor da minha equipa) ──────────────────────
    final shotsData = await supabase
        .from('shot_locations')
        .select()
        .eq('game_id', gameId);

    // IDs da minha equipa
    final Set<String> myPlayerIds =
        myPlayers.map((p) => p['id'].toString()).toSet();

    // Separa os tiros: todos da minha equipa, depois por jogador
    final List<_ShotDot> myTeamShots = [];
    final Map<String, List<_ShotDot>> shotsByPlayer = {};

    for (var shot in shotsData) {
      final memberId = shot['member_id'].toString();
      if (!myPlayerIds.contains(memberId)) continue;

      final dot = _ShotDot(
        relX: double.tryParse(shot['relative_x'].toString()) ?? 0.5,
        relY: double.tryParse(shot['relative_y'].toString()) ?? 0.5,
        isMake: shot['is_make'] == true,
      );
      myTeamShots.add(dot);
      shotsByPlayer.putIfAbsent(memberId, () => []).add(dot);
    }

    // ── Tabela de estatísticas (Apenas a minha equipa) ────────────────────
    List<List<String>> myTeamTable =
        _buildTeamTableData(myPlayers, statsMap);

    // ════════════════════════════════════════════════════════════════════════
    // CONSTRUÇÃO DO PDF
    // ════════════════════════════════════════════════════════════════════════
    final pdf = pw.Document();

    // ── PÁGINA 1: Box Score ──────────────────────────────────────────────
    pdf.addPage(
      pw.Page(
        pageFormat: PdfPageFormat.a4.landscape,
        margin: const pw.EdgeInsets.all(14),
        build: (pw.Context context) {
          return pw.FittedBox(
            fit: pw.BoxFit.scaleDown,
            child: pw.Container(
              width: PdfPageFormat.a4.landscape.availableWidth,
              child: pw.Column(
                crossAxisAlignment: pw.CrossAxisAlignment.start,
                children: [
                  pw.Row(
                    mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
                    children: [
                      pw.Text('Relatório Estatístico',
                          style: pw.TextStyle(
                              fontSize: 22,
                              fontWeight: pw.FontWeight.bold)),
                      pw.Column(
                        crossAxisAlignment: pw.CrossAxisAlignment.end,
                        children: [
                          pw.Text('$myTeam  vs  $opponentTeam',
                              style: pw.TextStyle(
                                  fontSize: 15,
                                  fontWeight: pw.FontWeight.bold)),
                          pw.Text('Resultado: $myScore — $opponentScore',
                              style: const pw.TextStyle(fontSize: 13)),
                          pw.Text('Época: $season',
                              style: const pw.TextStyle(fontSize: 11)),
                        ],
                      ),
                    ],
                  ),
                  pw.SizedBox(height: 12),

                  pw.Text('Equipa: $myTeam',
                      style: pw.TextStyle(
                          fontSize: 14,
                          fontWeight: pw.FontWeight.bold,
                          color: const PdfColor.fromInt(0xFFA00000))),
                  pw.SizedBox(height: 8),

                  pw.Text('Pontos e Lançamentos',
                      style: pw.TextStyle(
                          fontSize: 10,
                          fontWeight: pw.FontWeight.bold,
                          color: PdfColors.grey700)),
                  pw.SizedBox(height: 2),
                  _buildPdfTablePart1(
                      myTeamTable, const PdfColor.fromInt(0xFFA00000)),

                  pw.SizedBox(height: 14),

                  pw.Text('Outras Estatísticas (Ressaltos, Faltas, Turnovers, etc.)',
                      style: pw.TextStyle(
                          fontSize: 10,
                          fontWeight: pw.FontWeight.bold,
                          color: PdfColors.grey700)),
                  pw.SizedBox(height: 2),
                  _buildPdfTablePart2(
                      myTeamTable, const PdfColor.fromInt(0xFFA00000)),

                  pw.SizedBox(height: 16),

                  pw.Row(
                    crossAxisAlignment: pw.CrossAxisAlignment.start,
                    children: [
                      _buildSummaryBox('Melhor Marcador',
                          gameData['top_pts_name'] ?? '---'),
                      pw.SizedBox(width: 10),
                      _buildSummaryBox('Melhor Ressaltador',
                          gameData['top_rbs_name'] ?? '---'),
                      pw.SizedBox(width: 10),
                      _buildSummaryBox('Melhor Passador',
                          gameData['top_ast_name'] ?? '---'),
                      pw.SizedBox(width: 10),
                      _buildSummaryBox(
                          'MVP', gameData['mvp_name'] ?? '---'),
                    ],
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );

    // ── PÁGINA 2: Mapa de Calor — Equipa completa ────────────────────────
    if (myTeamShots.isNotEmpty) {
      pdf.addPage(
        pw.Page(
          pageFormat: PdfPageFormat.a4.landscape,
          margin: const pw.EdgeInsets.all(20),
          build: (pw.Context context) {
            return pw.Column(
              crossAxisAlignment: pw.CrossAxisAlignment.start,
              children: [
                _heatmapPageHeader('MAPA DE CALOR — $myTeam (Equipa Completa)',
                    const PdfColor.fromInt(0xFFA00000)),
                pw.SizedBox(height: 12),
                pw.Expanded(
                  child: pw.Center(
                    child: pw.CustomPaint(
                      size: const PdfPoint(360, 360),
                      painter: (canvas, size) =>
                          _paintCourt(canvas, size, myTeamShots),
                    ),
                  ),
                ),
                pw.SizedBox(height: 10),
                _heatmapLegend(),
              ],
            );
          },
        ),
      );
    }

    // ── PÁGINAS 3+: Mapa de Calor por Jogador (4 por folha) ──────────────
    // 👇 FILTRO ATIVO: Só entra aqui quem tiver tiros na lista "shotsByPlayer"!
    final activePlayers = myPlayers.where((p) {
      final pid = p['id'].toString();
      return shotsByPlayer[pid] != null && shotsByPlayer[pid]!.isNotEmpty;
    }).toList();

    for (int i = 0; i < activePlayers.length; i += 4) {
      final chunk = activePlayers.sublist(i, math.min(i + 4, activePlayers.length));

      pdf.addPage(
        pw.Page(
          pageFormat: PdfPageFormat.a4.landscape,
          margin: const pw.EdgeInsets.all(20),
          build: (pw.Context context) {
            return pw.Column(
              crossAxisAlignment: pw.CrossAxisAlignment.start,
              children: [
                _heatmapPageHeader('MAPAS DE CALOR INDIVIDUAIS', const PdfColor.fromInt(0xFFA00000)),
                pw.SizedBox(height: 12),
                pw.Expanded(
                  child: pw.Column(
                    children: [
                      if (chunk.isNotEmpty)
                        pw.Expanded(
                          child: pw.Row(
                            mainAxisAlignment: pw.MainAxisAlignment.center,
                            children: [
                              _buildPlayerHeatmap(chunk[0], shotsByPlayer[chunk[0]['id'].toString()]!, statsMap[chunk[0]['id'].toString()] ?? {}),
                              pw.SizedBox(width: 40),
                              chunk.length > 1 ? _buildPlayerHeatmap(chunk[1], shotsByPlayer[chunk[1]['id'].toString()]!, statsMap[chunk[1]['id'].toString()] ?? {}) : pw.Container(),
                            ],
                          ),
                        ),
                      pw.SizedBox(height: 12),
                      if (chunk.length > 2)
                        pw.Expanded(
                          child: pw.Row(
                            mainAxisAlignment: pw.MainAxisAlignment.center,
                            children: [
                              _buildPlayerHeatmap(chunk[2], shotsByPlayer[chunk[2]['id'].toString()]!, statsMap[chunk[2]['id'].toString()] ?? {}),
                              pw.SizedBox(width: 40),
                              chunk.length > 3 ? _buildPlayerHeatmap(chunk[3], shotsByPlayer[chunk[3]['id'].toString()]!, statsMap[chunk[3]['id'].toString()] ?? {}) : pw.Container(),
                            ],
                          ),
                        ),
                    ],
                  ),
                ),
                pw.SizedBox(height: 10),
                _heatmapLegend(),
              ],
            );
          },
        ),
      );
    }

    await Printing.layoutPdf(
      onLayout: (PdfPageFormat format) async => pdf.save(),
      name: 'BoxScore_$myTeam.pdf',
    );
  }

  // ════════════════════════════════════════════════════════════════════════════
  // WIDGET DO MAPA DE CALOR INDIVIDUAL
  // ════════════════════════════════════════════════════════════════════════════
  static pw.Widget _buildPlayerHeatmap(dynamic player, List<_ShotDot> shots, Map<String, dynamic> stats) {
    final String playerName = player['name']?.toString() ?? 'Jogador';
    final String playerNumber = player['number']?.toString() ?? '0';
    
    final int pts = stats['pts'] ?? 0;
    final int fgm = stats['fgm'] ?? 0;
    final int fga = stats['fga'] ?? 0;
    final String fgPct = fga > 0 ? '${((fgm / fga) * 100).toStringAsFixed(0)}%' : '0%';

    return pw.Container(
      width: 250,
      padding: const pw.EdgeInsets.all(8),
      decoration: pw.BoxDecoration(
        color: PdfColors.white,
        border: pw.Border.all(color: PdfColors.grey300),
        borderRadius: const pw.BorderRadius.all(pw.Radius.circular(6)),
      ),
      child: pw.Column(
        crossAxisAlignment: pw.CrossAxisAlignment.center,
        children: [
          pw.Text('#$playerNumber $playerName', style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 11, color: const PdfColor.fromInt(0xFFA00000))),
          pw.SizedBox(height: 4),
          pw.Text('PTS: $pts | FG: $fgm/$fga ($fgPct)', style: const pw.TextStyle(fontSize: 9, color: PdfColors.grey700)),
          pw.SizedBox(height: 8),
          pw.Expanded(
            child: pw.Center(
              child: pw.CustomPaint(
                size: const PdfPoint(180, 180),
                painter: (canvas, size) => _paintCourt(canvas, size, shots),
              )
            )
          )
        ]
      )
    );
  }

  // ════════════════════════════════════════════════════════════════════════════
  // CORREÇÃO: DESENHO DO CAMPO E LINHAS ADAPTADAS
  // ════════════════════════════════════════════════════════════════════════════

  static void _paintCourt(PdfGraphics canvas, PdfPoint size, List<_ShotDot> shots) {
    final double w = size.x;
    final double h = size.y;
    final double basketX = w / 2;

    // Fundo Amarelo (Toda a área)
    canvas
      ..setFillColor(const PdfColor.fromInt(0xFFDFAB00))
      ..drawRect(0, 0, w, h)
      ..fillPath();

    final double margin = w * 0.10;
    final double length = h * 0.35;
    final double larguraDoArco = (w / 2) - margin;
    final double alturaDoArco = larguraDoArco * 0.30;
    final double totalArcoHeight = alturaDoArco * 4;

    // ── 1. LINHAS BRANCAS ───────────────────────────────────────────────
    canvas.setStrokeColor(PdfColors.white);
    canvas.setLineWidth(2.0);

    _drawLine(canvas, h, margin, 0, margin, length);
    _drawLine(canvas, h, w - margin, 0, w - margin, length);
    _drawLine(canvas, h, 0, length, margin, length);
    _drawLine(canvas, h, w - margin, length, w, length);
    
    // Arco 3pts
    _drawEllipseArc(canvas, h, basketX, length, larguraDoArco, totalArcoHeight / 2, 0, math.pi);

    double sXL = basketX + (larguraDoArco * math.cos(math.pi * 0.75));
    double sYL = length + ((totalArcoHeight / 2) * math.sin(math.pi * 0.75));
    double sXR = basketX + (larguraDoArco * math.cos(math.pi * 0.25));
    double sYR = length + ((totalArcoHeight / 2) * math.sin(math.pi * 0.25));

    _drawLine(canvas, h, sXL, sYL, 0, h * 0.85);
    _drawLine(canvas, h, sXR, sYR, w, h * 0.85);

    // ── 2. LINHAS PRETAS ─────────────────────────────────────────────────
    canvas.setStrokeColor(PdfColors.black);
    canvas.setLineWidth(1.5);

    final double pW = w * 0.28;
    final double pH = h * 0.38;
    
    // Garrafão
    _drawRect(canvas, h, basketX - pW / 2, 0, pW, pH);

    // Círculo Lances Livres
    final double ftR = pW / 2;
    _drawEllipseArc(canvas, h, basketX, pH, ftR, ftR, 0, math.pi);
    // Tracejado
    for (int i = 0; i < 10; i++) {
      _drawEllipseArc(canvas, h, basketX, pH, ftR, ftR, math.pi + (i * 2 * (math.pi / 20)), math.pi / 20);
    }

    // Linhas oblíquas do garrafão
    _drawLine(canvas, h, basketX - pW / 2, pH, sXL, sYL); 
    _drawLine(canvas, h, basketX + pW / 2, pH, sXR, sYR); 

    // Meio Campo
    _drawEllipseArc(canvas, h, basketX, h, w * 0.12, w * 0.12, math.pi, math.pi);
    
    // Cesto e Tabela
    _drawCircle(canvas, h, basketX, h * 0.12, w * 0.02);
    _drawLine(canvas, h, basketX - w * 0.08, h * 0.12 - 5, basketX + w * 0.08, h * 0.12 - 5);

    // ── 3. TIROS ─────────────────────────────────────────────────────────
    for (final shot in shots) {
      final double px = shot.relX * w;
      final double py = shot.relY * h;

      final PdfColor dotColor = shot.isMake ? PdfColors.green600 : PdfColors.red600;

      // Desenha Círculo Colorido
      _fillCircle(canvas, h, px, py, 6, dotColor);

      // Símbolos
      canvas.setStrokeColor(PdfColors.white);
      canvas.setLineWidth(1.2);
      if (shot.isMake) {
        _drawLine(canvas, h, px - 3, py + 1.5, px - 0.5, py - 3); 
        _drawLine(canvas, h, px - 0.5, py - 3, px + 4.0, py + 3.5); 
      } else {
        _drawLine(canvas, h, px - 3, py - 3, px + 3, py + 3);
        _drawLine(canvas, h, px + 3, py - 3, px - 3, py + 3);
      }
    }
  }

  // ── Helpers com inversão automática do Eixo Y para casar com Flutter ──
  static void _drawLine(PdfGraphics c, double canvasH, double x1, double y1, double x2, double y2) {
    c.moveTo(x1, canvasH - y1);
    c.lineTo(x2, canvasH - y2);
    c.strokePath();
  }

  static void _lineRaw(PdfGraphics c, double x1, double y1, double x2, double y2) {
    c.moveTo(x1, y1);
    c.lineTo(x2, y2);
    c.strokePath();
  }

  static void _drawRect(PdfGraphics c, double canvasH, double x, double y, double width, double height) {
    c.drawRect(x, canvasH - (y + height), width, height);
    c.strokePath();
  }

  static void _drawCircle(PdfGraphics c, double canvasH, double cx, double cy, double r) {
    c.drawEllipse(cx, canvasH - cy, r, r);
    c.strokePath();
  }

  static void _fillCircle(PdfGraphics c, double canvasH, double cx, double cy, double r, PdfColor color) {
    c.setFillColor(color);
    c.drawEllipse(cx, canvasH - cy, r, r);
    c.fillPath();
  }

  static void _drawEllipseArc(PdfGraphics c, double canvasH, double cx, double cy, double rx, double ry, double startAngle, double sweepAngle) {
    const int steps = 30;
    final double step = sweepAngle / steps;
    double angle = startAngle;
    
    double fx = cx + rx * math.cos(angle);
    double fy = cy + ry * math.sin(angle);
    c.moveTo(fx, canvasH - fy);
    
    for (int i = 1; i <= steps; i++) {
      angle += step;
      fx = cx + rx * math.cos(angle);
      fy = cy + ry * math.sin(angle);
      c.lineTo(fx, canvasH - fy);
    }
    c.strokePath();
  }

  // ════════════════════════════════════════════════════════════════════════════
  // TABELAS DE ESTATÍSTICAS
  // ════════════════════════════════════════════════════════════════════════════

  static List<List<String>> _buildTeamTableData(
      List<dynamic> players, Map<String, Map<String, dynamic>> statsMap) {
    List<List<String>> tableData = [];

    int tPts = 0, tFgm = 0, tFga = 0, tFtm = 0, tFta = 0, tFls = 0;
    int tOrb = 0, tDrb = 0, tStl = 0, tAst = 0, tTov = 0, tBlk = 0;
    int tP3m = 0, tP2m = 0, tP3a = 0, tP2a = 0;
    int tSo = 0, tIl = 0, tLi = 0, tPa = 0, tTresS = 0, tDr = 0;
    int tSec = 0;

    players.sort((a, b) {
      int numA = int.tryParse(a['number']?.toString() ?? '0') ?? 0;
      int numB = int.tryParse(b['number']?.toString() ?? '0') ?? 0;
      return numA.compareTo(numB);
    });

    for (var p in players) {
      String id = p['id'].toString();
      var s = statsMap[id] ?? {};

      int pts = s['pts'] ?? 0;
      int fgm = s['fgm'] ?? 0;
      int fga = s['fga'] ?? 0;
      int ftm = s['ftm'] ?? 0;
      int fta = s['fta'] ?? 0;
      int p2m = s['p2m'] ?? 0;
      int p2a = s['p2a'] ?? 0;
      int p3m = s['p3m'] ?? 0;
      int p3a = s['p3a'] ?? 0;
      int fls = s['fls'] ?? 0;
      int orb = s['orb'] ?? 0;
      int drb = s['drb'] ?? 0;
      int stl = s['stl'] ?? 0;
      int ast = s['ast'] ?? 0;
      int tov = s['tov'] ?? 0;
      int blk = s['blk'] ?? 0;
      int so  = s['so'] ?? 0;
      int il  = s['il'] ?? 0;
      int li  = s['li'] ?? 0;
      int pa  = s['pa'] ?? 0;
      int tresS = s['tres_seg'] ?? 0;
      int dr  = s['dr'] ?? 0;
      int sec = s['minutos_jogados'] ?? 0;

      tPts += pts; tFgm += fgm; tFga += fga; tFtm += ftm; tFta += fta;
      tFls += fls; tOrb += orb; tDrb += drb; tStl += stl;
      tAst += ast; tTov += tov; tBlk += blk;
      tP3m += p3m; tP2m += p2m; tP3a += p3a; tP2a += p2a;
      tSo += so; tIl += il; tLi += li; tPa += pa;
      tTresS += tresS; tDr += dr; tSec += sec;

      String p2Pct = p2a > 0 ? '${((p2m / p2a) * 100).toStringAsFixed(0)}%' : '0%';
      String p3Pct = p3a > 0 ? '${((p3m / p3a) * 100).toStringAsFixed(0)}%' : '0%';
      String fgPct = fga > 0 ? '${((fgm / fga) * 100).toStringAsFixed(0)}%' : '0%';
      String ftPct = fta > 0 ? '${((ftm / fta) * 100).toStringAsFixed(0)}%' : '0%';

      String minStr = _secToMin(sec);

      tableData.add([
        p['number']?.toString() ?? '-',
        p['name']?.toString() ?? '?',
        minStr,
        pts.toString(),
        p2m.toString(), p2a.toString(), p2Pct,
        p3m.toString(), p3a.toString(), p3Pct,
        fgm.toString(), fga.toString(), fgPct,
        ftm.toString(), fta.toString(), ftPct,
        orb.toString(), drb.toString(), (orb + drb).toString(),
        stl.toString(), ast.toString(), tov.toString(), blk.toString(), fls.toString(),
        so.toString(), il.toString(), li.toString(),
        pa.toString(), tresS.toString(), dr.toString(),
      ]);
    }

    if (tableData.isEmpty) {
      tableData.add(List.filled(30, '0')..[0] = '-'..[1] = 'Sem jogadores');
    }

    String tP2Pct = tP2a > 0 ? '${((tP2m / tP2a) * 100).toStringAsFixed(0)}%' : '0%';
    String tP3Pct = tP3a > 0 ? '${((tP3m / tP3a) * 100).toStringAsFixed(0)}%' : '0%';
    String tFgPct = tFga > 0 ? '${((tFgm / tFga) * 100).toStringAsFixed(0)}%' : '0%';
    String tFtPct = tFta > 0 ? '${((tFtm / tFta) * 100).toStringAsFixed(0)}%' : '0%';

    tableData.add([
      '', 'TOTAIS', _secToMin(tSec), tPts.toString(),
      tP2m.toString(), tP2a.toString(), tP2Pct,
      tP3m.toString(), tP3a.toString(), tP3Pct,
      tFgm.toString(), tFga.toString(), tFgPct,
      tFtm.toString(), tFta.toString(), tFtPct,
      tOrb.toString(), tDrb.toString(), (tOrb + tDrb).toString(),
      tStl.toString(), tAst.toString(), tTov.toString(), tBlk.toString(), tFls.toString(),
      tSo.toString(), tIl.toString(), tLi.toString(),
      tPa.toString(), tTresS.toString(), tDr.toString(),
    ]);

    return tableData;
  }

  static String _secToMin(int sec) {
    final m = sec ~/ 60;
    final s = sec % 60;
    return '${m.toString().padLeft(2, '0')}:${s.toString().padLeft(2, '0')}';
  }

  static pw.Widget _buildPdfTablePart1(List<List<String>> data, PdfColor headerColor) {
    final hBold = pw.TextStyle(color: PdfColors.white, fontWeight: pw.FontWeight.bold, fontSize: 9);
    final hSub = pw.TextStyle(color: PdfColors.white, fontWeight: pw.FontWeight.bold, fontSize: 8);
    final cell = const pw.TextStyle(fontSize: 9);
    final cellBold = pw.TextStyle(fontSize: 9, fontWeight: pw.FontWeight.bold);

    return pw.Table(
      border: pw.TableBorder.all(color: PdfColors.grey400, width: 0.5),
      columnWidths: {
        0: const pw.FlexColumnWidth(1.2),
        1: const pw.FlexColumnWidth(4.5),
        2: const pw.FlexColumnWidth(2.0),
        3: const pw.FlexColumnWidth(1.5),
        4: const pw.FlexColumnWidth(4.5),
        5: const pw.FlexColumnWidth(4.5),
        6: const pw.FlexColumnWidth(4.5),
        7: const pw.FlexColumnWidth(4.5),
      },
      children: [
        pw.TableRow(
          decoration: pw.BoxDecoration(color: headerColor),
          children: [
            _sh('Nº', hSub),
            _sh('NOME', hSub, left: true),
            _sh('MIN', hSub),
            _sh('PTS', hSub),
            _groupHeader('2 PONTOS', hBold, hSub),
            _groupHeader('3 PONTOS', hBold, hSub),
            _groupHeader('GLOBAL', hBold, hSub),
            _groupHeader('L. LIVRES', hBold, hSub),
          ],
        ),
        ...data.map((row) {
          bool isTotais = row[1] == 'TOTAIS';
          var s = isTotais ? cellBold : cell;
          PdfColor? bg = isTotais ? PdfColors.grey200 : null;

          return pw.TableRow(
            decoration: pw.BoxDecoration(color: bg),
            children: [
              _sd(row[0], s),
              _sd(row[1], s, left: true),
              _sd(row[2], s),   
              _sd(row[3], s),   
              _groupData(row[4], row[5], row[6], s),    
              _groupData(row[7], row[8], row[9], s),    
              _groupData(row[10], row[11], row[12], s), 
              _groupData(row[13], row[14], row[15], s), 
            ],
          );
        }),
      ],
    );
  }

  static pw.Widget _buildPdfTablePart2(List<List<String>> data, PdfColor headerColor) {
    final hSub = pw.TextStyle(color: PdfColors.white, fontWeight: pw.FontWeight.bold, fontSize: 8);
    final cell = const pw.TextStyle(fontSize: 9);
    final cellBold = pw.TextStyle(fontSize: 9, fontWeight: pw.FontWeight.bold);

    return pw.Table(
      border: pw.TableBorder.all(color: PdfColors.grey400, width: 0.5),
      columnWidths: {
        0: const pw.FlexColumnWidth(1.2), 
        1: const pw.FlexColumnWidth(4.5), 
        2: const pw.FlexColumnWidth(1.5), 
        3: const pw.FlexColumnWidth(1.5), 
        4: const pw.FlexColumnWidth(1.5), 
        5: const pw.FlexColumnWidth(1.5), 
        6: const pw.FlexColumnWidth(1.5), 
        7: const pw.FlexColumnWidth(1.5), 
        8: const pw.FlexColumnWidth(1.5), 
        9: const pw.FlexColumnWidth(1.5), 
        10: const pw.FlexColumnWidth(1.5), 
        11: const pw.FlexColumnWidth(1.5), 
        12: const pw.FlexColumnWidth(1.5), 
        13: const pw.FlexColumnWidth(1.5), 
        14: const pw.FlexColumnWidth(1.5), 
        15: const pw.FlexColumnWidth(1.5), 
      },
      children: [
        pw.TableRow(
          decoration: pw.BoxDecoration(color: headerColor),
          children: [
            _sh('Nº', hSub),
            _sh('NOME', hSub, left: true),
            _sh('RO', hSub),
            _sh('RD', hSub),
            _sh('TR', hSub),
            _sh('BR', hSub),
            _sh('AS', hSub),
            _sh('BP', hSub),
            _sh('BLK', hSub),
            _sh('FLS', hSub),
            _sh('SO', hSub),
            _sh('IL', hSub),
            _sh('LI', hSub),
            _sh('PA', hSub),
            _sh('3S', hSub),
            _sh('DR', hSub),
          ],
        ),
        ...data.map((row) {
          bool isTotais = row[1] == 'TOTAIS';
          var s = isTotais ? cellBold : cell;
          PdfColor? bg = isTotais ? PdfColors.grey200 : null;

          return pw.TableRow(
            decoration: pw.BoxDecoration(color: bg),
            children: [
              _sd(row[0], s),
              _sd(row[1], s, left: true),
              _sd(row[16], s),
              _sd(row[17], s),
              _sd(row[18], s),
              _sd(row[19], s),
              _sd(row[20], s),
              _sd(row[21], s),
              _sd(row[22], s),
              _sd(row[23], s),
              _sd(row[24], s),
              _sd(row[25], s),
              _sd(row[26], s),
              _sd(row[27], s),
              _sd(row[28], s),
              _sd(row[29], s),
            ],
          );
        }),
      ],
    );
  }

  static pw.Widget _sh(String text, pw.TextStyle style, {bool left = false}) {
    return pw.Container(
      alignment: left ? pw.Alignment.centerLeft : pw.Alignment.center,
      padding: const pw.EdgeInsets.symmetric(vertical: 4, horizontal: 4),
      child: pw.Text(text, style: style),
    );
  }

  static pw.Widget _sd(String text, pw.TextStyle style, {bool left = false}) {
    return pw.Container(
      alignment: left ? pw.Alignment.centerLeft : pw.Alignment.center,
      padding: const pw.EdgeInsets.symmetric(vertical: 4, horizontal: 4),
      child: pw.Text(text, style: style),
    );
  }

  static pw.Widget _groupHeader(
      String title, pw.TextStyle hStyle, pw.TextStyle sStyle) {
    return pw.Column(
      children: [
        pw.Container(
          width: double.infinity,
          alignment: pw.Alignment.center,
          padding: const pw.EdgeInsets.symmetric(vertical: 2),
          decoration: const pw.BoxDecoration(
            border: pw.Border(
                bottom: pw.BorderSide(color: PdfColors.white, width: 0.5)),
          ),
          child: pw.Text(title, style: hStyle),
        ),
        pw.Row(children: [
          pw.Expanded(
              child: pw.Container(
                  alignment: pw.Alignment.center,
                  padding: const pw.EdgeInsets.symmetric(vertical: 2),
                  child: pw.Text('C', style: sStyle))),
          pw.Container(width: 0.5, height: 10, color: PdfColors.white),
          pw.Expanded(
              child: pw.Container(
                  alignment: pw.Alignment.center,
                  padding: const pw.EdgeInsets.symmetric(vertical: 2),
                  child: pw.Text('T', style: sStyle))),
          pw.Container(width: 0.5, height: 10, color: PdfColors.white),
          pw.Expanded(
              child: pw.Container(
                  alignment: pw.Alignment.center,
                  padding: const pw.EdgeInsets.symmetric(vertical: 2),
                  child: pw.Text('%', style: sStyle))),
        ]),
      ],
    );
  }

  static pw.Widget _groupData(
      String c, String t, String pct, pw.TextStyle style) {
    return pw.Row(children: [
      pw.Expanded(
          child: pw.Container(
              alignment: pw.Alignment.center,
              padding: const pw.EdgeInsets.symmetric(vertical: 4),
              child: pw.Text(c, style: style))),
      pw.Container(width: 0.5, height: 12, color: PdfColors.grey400),
      pw.Expanded(
          child: pw.Container(
              alignment: pw.Alignment.center,
              padding: const pw.EdgeInsets.symmetric(vertical: 4),
              child: pw.Text(t, style: style))),
      pw.Container(width: 0.5, height: 12, color: PdfColors.grey400),
      pw.Expanded(
          child: pw.Container(
              alignment: pw.Alignment.center,
              padding: const pw.EdgeInsets.symmetric(vertical: 4),
              child: pw.Text(pct, style: style))),
    ]);
  }

  static pw.Widget _heatmapPageHeader(String title, PdfColor color) {
    return pw.Container(
      width: double.infinity,
      padding: const pw.EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: pw.BoxDecoration(
        color: color,
        borderRadius: const pw.BorderRadius.all(pw.Radius.circular(6)),
      ),
      child: pw.Text(
        title,
        style: pw.TextStyle(
            color: PdfColors.white,
            fontSize: 14,
            fontWeight: pw.FontWeight.bold),
      ),
    );
  }

  static pw.Widget _heatmapLegend() {
    return pw.Row(
      mainAxisAlignment: pw.MainAxisAlignment.center,
      children: [
        pw.Container(width: 12, height: 12,
            decoration: const pw.BoxDecoration(
                color: PdfColors.green600, shape: pw.BoxShape.circle)),
        pw.SizedBox(width: 4),
        pw.Text('Cesto marcado', style: pw.TextStyle(fontSize: 10)),
        pw.SizedBox(width: 20),
        pw.Container(width: 12, height: 12,
            decoration: const pw.BoxDecoration(
                color: PdfColors.red600, shape: pw.BoxShape.circle)),
        pw.SizedBox(width: 4),
        pw.Text('Cesto falhado', style: pw.TextStyle(fontSize: 10)),
      ],
    );
  }

  static pw.Widget _buildSummaryBox(String title, String value) {
    return pw.Container(
      width: 120,
      decoration: pw.BoxDecoration(
        border: pw.TableBorder.all(color: PdfColors.black, width: 1),
      ),
      child: pw.Column(children: [
        pw.Container(
          width: double.infinity,
          padding: const pw.EdgeInsets.all(6),
          color: const PdfColor.fromInt(0xFFA00000),
          child: pw.Text(title,
              style: pw.TextStyle(
                  color: PdfColors.white,
                  fontSize: 9,
                  fontWeight: pw.FontWeight.bold),
              textAlign: pw.TextAlign.center),
        ),
        pw.Container(
          width: double.infinity,
          padding: const pw.EdgeInsets.all(8),
          child: pw.Text(value,
              style: pw.TextStyle(
                  fontSize: 10, fontWeight: pw.FontWeight.bold),
              textAlign: pw.TextAlign.center),
        ),
      ]),
    );
  }
}