import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../../core/api/api_client.dart';
import '../../auth/presentation/sessao_controller.dart';
import '../data/ciclo_vida_repository.dart';
import '../../../core/firebase/provedores.dart';

/// Os provedores mudaram de casa em `MG-7` (`core/firebase/provedores.dart`),
/// onde a escolha entre HTTP e Firebase é feita. Reexportados aqui para a
/// apresentação e os testes continuarem importando do mesmo lugar de sempre —
/// a troca de backend não tem por que aparecer na tela.
export '../../../core/firebase/provedores.dart'
    show cicloVidaRepositoryProvider;

/// Encerramento do bolão (CV-1/CV-3) e o resultado final.
///
/// O campeão é **calculado na leitura**, nunca congelado: correção de placar
/// troca o campeão mesmo depois do encerramento (decisão de 03/08). Por isso a
/// tela fala de "resultado atual", não de "resultado definitivo".
class EncerramentoDialog extends ConsumerStatefulWidget {
  const EncerramentoDialog({
    required this.poolId,
    this.jaEncerrado = false,
    super.key,
  });

  final String poolId;

  /// Bolão já encerrado: a tela abre direto no resultado, sem oferecer ação.
  /// Sem isto o campeão só era visto no **instante** em que o admin encerrava —
  /// depois disso ninguém alcançava a tela, e o participante comum nunca a via.
  final bool jaEncerrado;

  @override
  ConsumerState<EncerramentoDialog> createState() => _EncerramentoDialogState();
}

class _EncerramentoDialogState extends ConsumerState<EncerramentoDialog> {
  Encerramento? _resultado;
  String? _erro;
  bool _trabalhando = false;

  @override
  void initState() {
    super.initState();
    if (widget.jaEncerrado) _carregar();
  }

  Future<void> _carregar() async {
    setState(() => _trabalhando = true);
    try {
      final r = await ref
          .read(cicloVidaRepositoryProvider)
          .lerEncerramento(widget.poolId);
      if (!mounted) return;
      setState(() => _resultado = r);
    } on ApiError catch (e) {
      if (mounted) setState(() => _erro = e.mensagem);
    } finally {
      if (mounted) setState(() => _trabalhando = false);
    }
  }

  Future<void> _encerrar({required bool antecipado}) async {
    if (antecipado && !await _confirmarAntecipado()) return;

    setState(() {
      _trabalhando = true;
      _erro = null;
    });
    try {
      final repo = ref.read(cicloVidaRepositoryProvider);
      final r = antecipado
          ? await repo.encerrarAntecipado(widget.poolId)
          : await repo.encerrar(widget.poolId);
      if (!mounted) return;
      setState(() => _resultado = r);
    } on ApiError catch (e) {
      // "ainda há jogo sem resultado" é a informação que o admin precisa para
      // decidir entre esperar e encerrar antecipadamente.
      if (mounted) setState(() => _erro = e.mensagem);
    } finally {
      if (mounted) setState(() => _trabalhando = false);
    }
  }

  Future<bool> _confirmarAntecipado() async {
    final ok = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Encerrar antes do fim?'),
        content: const Text(
          'Isto é irreversível: o bolão fecha agora, com a pontuação que '
          'existe, e não há como reabri-lo. Ninguém mais palpita, e o título '
          'fica marcado como encerramento antecipado — não vale o mesmo que '
          'ganhar o campeonato inteiro.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('Cancelar'),
          ),
          FilledButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: const Text('Encerrar agora'),
          ),
        ],
      ),
    );
    return ok == true;
  }

  @override
  Widget build(BuildContext context) {
    final r = _resultado;
    final sessao = ref.watch(sessaoProvider);
    final meuId = sessao is Autenticado ? sessao.conta.id : null;

    return AlertDialog(
      title: Text(
        r == null && !widget.jaEncerrado
            ? 'Encerrar o bolão'
            : 'Bolão encerrado',
      ),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          if (r == null && widget.jaEncerrado)
            // Só gira enquanto está buscando. Girar depois de falhar deixaria a
            // tela num spinner eterno com o motivo escondido embaixo.
            _trabalhando
                ? const Center(
                    child: Padding(
                      padding: EdgeInsets.all(8),
                      child: CircularProgressIndicator(),
                    ),
                  )
                : const Text('Não foi possível carregar o resultado agora.')
          else if (r == null) ...[
            const Text(
              'O encerramento normal só funciona quando todos os jogos do bolão '
              'tiverem resultado.',
            ),
            const SizedBox(height: 8),
            const Text(
              'Se algum jogo foi adiado sem data, o encerramento antecipado é a '
              'única saída — e fica registrado como tal.',
              style: TextStyle(fontSize: 12),
            ),
          ] else ...[
            Text(
              r.campeoes.length > 1
                  // Co-campeões não são "empate a resolver": é o resultado.
                  ? 'Co-campeões: ${r.campeoes.map((c) => c.displayName).join(', ')}'
                  : r.campeoes.isEmpty
                  ? 'Nenhum campeão: ninguém pontuou.'
                  : 'Campeão: ${r.campeoes.first.displayName}',
              style: const TextStyle(fontWeight: FontWeight.bold),
            ),
            if (r.campeoes.isNotEmpty) ...[
              const SizedBox(height: 4),
              Text('${r.campeoes.first.points} pontos'),
            ],
            if (r.campeoes.any((c) => c.userId == meuId)) ...[
              const SizedBox(height: 8),
              Text(
                r.campeoes.length > 1
                    ? 'Você dividiu o título.'
                    : 'Você é o campeão.',
              ),
            ],
            if (r.antecipado) ...[
              const SizedBox(height: 12),
              const Text(
                'Encerrado antecipadamente, antes da última rodada.',
                style: TextStyle(fontSize: 12),
              ),
            ],
            if (r.rankingFinal.isNotEmpty) ...[
              const Divider(height: 24),
              Text(
                'Classificação final',
                style: Theme.of(context).textTheme.labelLarge,
              ),
              const SizedBox(height: 4),
              // Dentro de um diálogo: limitado em altura e rolável, senão um
              // bolão de 20 pessoas estoura a tela.
              ConstrainedBox(
                constraints: const BoxConstraints(maxHeight: 180),
                child: SingleChildScrollView(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: r.rankingFinal
                        .map(
                          (l) => Padding(
                            padding: const EdgeInsets.symmetric(vertical: 2),
                            child: Text(
                              '${l.posicao}º  ${l.displayName} — ${l.points} pts',
                              style: const TextStyle(fontSize: 13),
                            ),
                          ),
                        )
                        .toList(),
                  ),
                ),
              ),
            ],
            const SizedBox(height: 12),
            const Text(
              'Se um placar for corrigido depois, a pontuação e o campeão são '
              'recalculados — nada fica congelado.',
              style: TextStyle(fontSize: 12),
            ),
          ],
          if (_erro != null) ...[
            const SizedBox(height: 12),
            Text(
              _erro!,
              style: TextStyle(
                color: Theme.of(context).colorScheme.error,
                fontSize: 12,
              ),
            ),
          ],
        ],
      ),
      actions: r != null || widget.jaEncerrado
          ? [
              // Falhou a leitura: oferecer retry é o que evita "fecha e abre de
              // novo" como única saída.
              if (r == null && widget.jaEncerrado && !_trabalhando)
                TextButton(
                  onPressed: _carregar,
                  child: const Text('Tentar de novo'),
                ),
              TextButton(
                onPressed: () => Navigator.of(context).pop(),
                child: const Text('Fechar'),
              ),
            ]
          : [
              TextButton(
                onPressed: () => Navigator.of(context).pop(),
                child: const Text('Cancelar'),
              ),
              TextButton(
                onPressed: _trabalhando
                    ? null
                    : () => _encerrar(antecipado: true),
                child: const Text('Encerrar agora'),
              ),
              FilledButton(
                onPressed: _trabalhando
                    ? null
                    : () => _encerrar(antecipado: false),
                child: const Text('Encerrar'),
              ),
            ],
    );
  }
}
