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/participantes_repository.dart';
import '../../../core/tema/tema.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 participantesRepositoryProvider;

/// Participantes do bolão.
///
/// Para o admin é a tela de cobrança: quem entrou, quem falta palpitar e as
/// ações de promover, remover e sair. Para o participante comum é só a lista —
/// a autorização é do servidor, e a UI não oferece o que vai dar 403.
class ParticipantesPage extends ConsumerStatefulWidget {
  const ParticipantesPage({
    required this.poolId,
    required this.matchday,
    required this.souAdmin,
    super.key,
  });

  final String poolId;
  final int matchday;
  final bool souAdmin;

  @override
  ConsumerState<ParticipantesPage> createState() => _ParticipantesPageState();
}

class _ParticipantesPageState extends ConsumerState<ParticipantesPage> {
  ListaParticipantes? _lista;
  StatusDaRodada? _status;
  String? _erro;
  bool _carregando = true;

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

  Future<void> _carregar() async {
    setState(() => _erro = null);
    final repo = ref.read(participantesRepositoryProvider);
    try {
      final lista = await repo.listar(widget.poolId);
      // O status da rodada é só do admin (PP-9). Falhar aqui não pode derrubar
      // a lista, que todo participante tem direito de ver.
      StatusDaRodada? status;
      if (widget.souAdmin) {
        try {
          status = await repo.statusDaRodada(widget.poolId, widget.matchday);
        } on ApiError catch (_) {
          status = null;
        }
      }
      if (!mounted) return;
      setState(() {
        _lista = lista;
        _status = status;
      });
    } on ApiError catch (e) {
      if (mounted) setState(() => _erro = e.mensagem);
    } finally {
      if (mounted) setState(() => _carregando = false);
    }
  }

  /// Quem está olhando é o criador do bolão?
  bool _euSouCriador(ListaParticipantes lista) {
    final sessao = ref.read(sessaoProvider);
    if (sessao is! Autenticado) return false;
    return lista.linhas.any((p) => p.userId == sessao.conta.id && p.isCreator);
  }

  Future<bool> _confirmar(String titulo, String detalhe, String acao) async {
    final ok = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(titulo),
        content: Text(detalhe),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('Cancelar'),
          ),
          FilledButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: Text(acao),
          ),
        ],
      ),
    );
    return ok == true;
  }

  Future<void> _executar(Future<void> Function() acao, String sucesso) async {
    try {
      await acao();
      if (!mounted) return;
      _avisar(sucesso, sucesso: true);
      await _carregar();
    } on ApiError catch (e) {
      // Conflitos têm texto próprio: "criador é admin permanente", "bolão
      // ficaria sem admin". Genérico aqui não ensina nada ao admin.
      if (mounted) _avisar(e.mensagem);
    }
  }

  void _avisar(String texto, {bool sucesso = false}) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(texto),
        backgroundColor: sucesso ? CoresDoApp.sucesso : null,
      ),
    );
  }

  Future<void> _promover(Participante p) async {
    if (!await _confirmar(
      'Tornar ${p.displayName} administrador?',
      'Ele vai poder convidar, corrigir placar e encerrar o bolão. Mais de um '
          'admin é permitido.',
      'Promover',
    )) {
      return;
    }
    await _executar(
      () => ref
          .read(participantesRepositoryProvider)
          .promover(widget.poolId, p.userId),
      '${p.displayName} agora é administrador',
    );
  }

  Future<void> _rebaixar(Participante p) async {
    if (!await _confirmar(
      'Remover a administração de ${p.displayName}?',
      'Ele continua participando e palpitando, só perde as ações de admin.',
      'Rebaixar',
    )) {
      return;
    }
    await _executar(
      () => ref
          .read(participantesRepositoryProvider)
          .rebaixar(widget.poolId, p.userId),
      '${p.displayName} deixou de ser administrador',
    );
  }

  Future<void> _remover(Participante p) async {
    if (!await _confirmar(
      'Remover ${p.displayName} do bolão?',
      'Os palpites já apurados dele continuam no histórico, mas ele não '
          'aparece mais no ranking e não volta pelo convite.',
      'Remover',
    )) {
      return;
    }
    await _executar(
      () => ref
          .read(participantesRepositoryProvider)
          .remover(widget.poolId, p.userId),
      '${p.displayName} foi removido',
    );
  }

  Future<void> _sair() async {
    if (!await _confirmar(
      'Sair deste bolão?',
      // Sem asterisco: o corpo do diálogo é `String` num `Text`, que não
      // interpreta markdown — apareciam os dois pares na tela.
      'A saída é definitiva: você não volta nem com um convite novo, e '
          'deixa de aparecer no ranking.',
      'Sair do bolão',
    )) {
      return;
    }
    try {
      await ref.read(participantesRepositoryProvider).sair(widget.poolId);
      if (!mounted) return;
      // Sem bolão não há tela: volta para a lista, que recarrega sozinha.
      Navigator.of(context).pop();
    } on ApiError catch (e) {
      if (mounted) _avisar(e.mensagem);
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_carregando) return const Center(child: CircularProgressIndicator());

    if (_erro != null && _lista == null) {
      return Center(
        child: Padding(
          padding: const EdgeInsets.all(32),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              const Icon(Icons.cloud_off, size: 48),
              const SizedBox(height: 12),
              Text(_erro!, textAlign: TextAlign.center),
              const SizedBox(height: 16),
              FilledButton(
                onPressed: _carregar,
                child: const Text('Tentar de novo'),
              ),
            ],
          ),
        ),
      );
    }

    final lista = _lista!;
    final sessao = ref.watch(sessaoProvider);
    final meuId = sessao is Autenticado ? sessao.conta.id : '';
    final status = {
      for (final s in _status?.linhas ?? const <StatusPalpite>[]) s.userId: s,
    };

    return RefreshIndicator(
      onRefresh: _carregar,
      child: ListView(
        padding: const EdgeInsets.only(bottom: 24),
        children: [
          if (lista.total == 1)
            // Bolão de uma pessoa é mensagem útil, não lista vazia: o que falta
            // é convidar, e é isso que precisa estar escrito.
            const Padding(
              padding: EdgeInsets.all(16),
              child: Text(
                'Só você por aqui. Use a ação de convite lá em cima para chamar '
                'a galera.',
              ),
            ),
          if (_status != null)
            Padding(
              padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
              child: Text(
                'Rodada ${_status!.matchday} · ${_status!.totalJogos} jogos',
                style: Theme.of(context).textTheme.labelLarge,
              ),
            ),
          ...lista.linhas.map(
            (p) => _LinhaParticipante(
              participante: p,
              status: status[p.userId],
              totalJogos: _status?.totalJogos,
              souEu: p.userId == meuId,
              // Ações de admin nunca aparecem para participante comum.
              podeAdministrar: widget.souAdmin,
              onPromover: () => _promover(p),
              onRebaixar: () => _rebaixar(p),
              onRemover: () => _remover(p),
            ),
          ),
          const Divider(height: 32),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16),
            // Criador é admin permanente e **nunca** consegue sair: o servidor
            // recusa com 409. Oferecer o botão a ele era prometer uma saída que
            // não existe — o mesmo erro do ícone de convite para não-admin.
            child: _euSouCriador(lista)
                ? Text(
                    'Você criou este bolão e é administrador permanente: não é '
                    'possível sair dele.',
                    style: TextStyle(
                      fontSize: 13,
                      color: Theme.of(context).colorScheme.outline,
                    ),
                  )
                : OutlinedButton.icon(
                    onPressed: _sair,
                    icon: const Icon(Icons.exit_to_app),
                    label: const Text('Sair do bolão'),
                  ),
          ),
        ],
      ),
    );
  }
}

class _LinhaParticipante extends StatelessWidget {
  const _LinhaParticipante({
    required this.participante,
    required this.status,
    required this.totalJogos,
    required this.souEu,
    required this.podeAdministrar,
    required this.onPromover,
    required this.onRebaixar,
    required this.onRemover,
  });

  final Participante participante;
  final StatusPalpite? status;
  final int? totalJogos;
  final bool souEu;
  final bool podeAdministrar;
  final VoidCallback onPromover;
  final VoidCallback onRebaixar;
  final VoidCallback onRemover;

  String? get _detalhe {
    if (!participante.ativo) return 'saiu do bolão';

    final s = status;
    final estadoDoPalpite = s == null
        ? null
        : switch (s.estado) {
            'COMPLETO' => 'palpitou em todos os jogos',
            'PARCIAL' =>
              'palpitou em ${s.feitos} de ${totalJogos ?? '?'} jogos',
            _ => 'ainda não palpitou',
          };

    // Para quem administra, a linha do criador explica **por que** não tem ação:
    // sem isso o admin procura o menu, não acha, e conclui que é defeito do app
    // (decisão do dono em 07/08 para `CC-9 FE-3`).
    //
    // A explicação **acompanha** o estado do palpite, nunca o substitui: saber
    // quem falta palpitar é o que o admin vem fazer aqui (PP-9).
    if (participante.isCreator && podeAdministrar) {
      const motivo = 'criou o bolão — não pode ser rebaixado nem removido';
      return estadoDoPalpite == null ? motivo : '$estadoDoPalpite · $motivo';
    }
    return estadoDoPalpite;
  }

  @override
  Widget build(BuildContext context) {
    final cores = Theme.of(context).colorScheme;
    final p = participante;
    final faltando = p.ativo && status != null && status!.estado != 'COMPLETO';

    return ListTile(
      leading: Icon(
        p.ativo ? Icons.person : Icons.person_off_outlined,
        color: p.ativo ? null : cores.outline,
      ),
      title: Text(
        p.displayName + (souEu ? ' (você)' : ''),
        style: TextStyle(
          fontWeight: souEu ? FontWeight.bold : null,
          // Quem saiu fica visível mas apagado: o histórico dele continua
          // existindo, e apagar a linha esconderia isso.
          color: p.ativo ? null : cores.outline,
        ),
      ),
      subtitle: _detalhe == null
          ? null
          : Text(
              _detalhe!,
              style: TextStyle(
                color: faltando ? cores.error : cores.outline,
                fontSize: 12,
              ),
            ),
      trailing: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          if (p.isCreator)
            const Chip(
              label: Text('criador', style: TextStyle(fontSize: 11)),
              visualDensity: VisualDensity.compact,
            )
          else if (p.isAdmin)
            const Chip(
              label: Text('admin', style: TextStyle(fontSize: 11)),
              visualDensity: VisualDensity.compact,
            ),
          // Criador é admin permanente (decisão de 03/08): nenhuma ação sobre
          // ele, nem promover nem remover.
          if (podeAdministrar && p.ativo && !p.isCreator)
            PopupMenuButton<String>(
              onSelected: (v) => switch (v) {
                'promover' => onPromover(),
                'rebaixar' => onRebaixar(),
                _ => onRemover(),
              },
              itemBuilder: (_) => [
                if (!p.isAdmin)
                  const PopupMenuItem(
                    value: 'promover',
                    child: Text('Tornar administrador'),
                  ),
                if (p.isAdmin)
                  const PopupMenuItem(
                    value: 'rebaixar',
                    child: Text('Remover administração'),
                  ),
                const PopupMenuItem(
                  value: 'remover',
                  child: Text('Remover do bolão'),
                ),
              ],
            ),
        ],
      ),
    );
  }
}
