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

/// Valores das regras em edição.
class ValoresDeRegras {
  const ValoresDeRegras({
    required this.exato,
    required this.vencedorSaldo,
    required this.vencedor,
    required this.ordemDesempate,
  });

  /// Padrão decidido no PRD. É o que aparece pré-selecionado na criação: o
  /// admin casual não quer configurar nada, e mudar isso é a exceção.
  static const padrao = ValoresDeRegras(
    exato: 10,
    vencedorSaldo: 5,
    vencedor: 3,
    ordemDesempate: ['EXACT_SCORES', 'WINNERS'],
  );

  final int exato;
  final int vencedorSaldo;
  final int vencedor;
  final List<String> ordemDesempate;

  bool get ehPadrao =>
      exato == padrao.exato &&
      vencedorSaldo == padrao.vencedorSaldo &&
      vencedor == padrao.vencedor &&
      _mesmaOrdem(ordemDesempate, padrao.ordemDesempate);

  static bool _mesmaOrdem(List<String> a, List<String> b) =>
      a.length == b.length &&
      List.generate(a.length, (i) => a[i] == b[i]).every((x) => x);

  ValoresDeRegras copiarCom({
    int? exato,
    int? vencedorSaldo,
    int? vencedor,
    List<String>? ordemDesempate,
  }) => ValoresDeRegras(
    exato: exato ?? this.exato,
    vencedorSaldo: vencedorSaldo ?? this.vencedorSaldo,
    vencedor: vencedor ?? this.vencedor,
    ordemDesempate: ordemDesempate ?? this.ordemDesempate,
  );

  /// A tabela precisa ser **monótona**: acertar mais não pode valer menos.
  /// Sem esta checagem o admin cria um bolão em que errar o saldo é melhor que
  /// acertar, e a briga aparece só na apuração.
  String? get inconsistencia {
    if (exato < vencedorSaldo || vencedorSaldo < vencedor) {
      return 'placar exato precisa valer pelo menos o mesmo que vencedor e '
          'saldo, que precisa valer pelo menos o mesmo que só o vencedor';
    }
    if (vencedor <= 0) {
      return 'acertar o vencedor precisa valer mais que zero, senão o bolão '
          'inteiro fica sem pontuação';
    }
    return null;
  }
}

/// Editor da tabela de pontos e da ordem de desempate.
///
/// Usado na criação (CC-2) e na edição pelo admin (CC-2 FE-3). Quem chama
/// decide se está habilitado — travado depois do primeiro palpite (CC-3).
class EditorDeRegras extends StatelessWidget {
  const EditorDeRegras({
    required this.valores,
    required this.onMudou,
    this.habilitado = true,
    super.key,
  });

  final ValoresDeRegras valores;
  final ValueChanged<ValoresDeRegras> onMudou;
  final bool habilitado;

  @override
  Widget build(BuildContext context) {
    final cores = Theme.of(context).colorScheme;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        _Linha(
          rotulo: 'Placar exato',
          valor: valores.exato,
          habilitado: habilitado,
          onMudou: (v) => onMudou(valores.copiarCom(exato: v)),
        ),
        _Linha(
          rotulo: 'Vencedor e saldo',
          valor: valores.vencedorSaldo,
          habilitado: habilitado,
          onMudou: (v) => onMudou(valores.copiarCom(vencedorSaldo: v)),
        ),
        _Linha(
          rotulo: 'Só o vencedor',
          valor: valores.vencedor,
          habilitado: habilitado,
          onMudou: (v) => onMudou(valores.copiarCom(vencedor: v)),
        ),
        const SizedBox(height: 8),
        Text('Desempate', style: Theme.of(context).textTheme.labelLarge),
        const SizedBox(height: 4),
        // Duas ordens possíveis, não uma lista arrastável: o ganho de
        // flexibilidade não paga a confusão numa tela que o admin usa uma vez.
        RadioGroup<String>(
          groupValue: valores.ordemDesempate.first,
          onChanged: (v) {
            // Travado depois do primeiro palpite: ignora em vez de desabilitar
            // o grupo, para o participante continuar **lendo** a regra.
            if (!habilitado || v == null) return;
            onMudou(
              valores.copiarCom(
                ordemDesempate: v == 'EXACT_SCORES'
                    ? const ['EXACT_SCORES', 'WINNERS']
                    : const ['WINNERS', 'EXACT_SCORES'],
              ),
            );
          },
          child: const Column(
            children: [
              RadioListTile<String>(
                value: 'EXACT_SCORES',
                dense: true,
                title: Text('Placares exatos, depois acertos de vencedor'),
              ),
              RadioListTile<String>(
                value: 'WINNERS',
                dense: true,
                title: Text('Acertos de vencedor, depois placares exatos'),
              ),
            ],
          ),
        ),
        if (valores.inconsistencia != null) ...[
          const SizedBox(height: 8),
          Text(
            valores.inconsistencia!,
            style: TextStyle(color: cores.error, fontSize: 12),
          ),
        ],
        if (!valores.ehPadrao && valores.inconsistencia == null) ...[
          const SizedBox(height: 8),
          Text(
            'Você saiu do padrão (10 / 5 / 3). Vale conferir com a galera antes '
            'do primeiro palpite — depois dele não muda mais.',
            style: TextStyle(color: cores.outline, fontSize: 12),
          ),
        ],
      ],
    );
  }
}

class _Linha extends StatelessWidget {
  const _Linha({
    required this.rotulo,
    required this.valor,
    required this.habilitado,
    required this.onMudou,
  });

  final String rotulo;
  final int valor;
  final bool habilitado;
  final ValueChanged<int> onMudou;

  @override
  Widget build(BuildContext context) => Padding(
    padding: const EdgeInsets.symmetric(vertical: 4),
    child: Row(
      children: [
        SizedBox(
          width: 72,
          child: Semantics(
            label: 'Pontos por $rotulo',
            child: TextFormField(
              initialValue: valor.toString(),
              enabled: habilitado,
              textAlign: TextAlign.center,
              keyboardType: TextInputType.number,
              inputFormatters: [
                FilteringTextInputFormatter.digitsOnly,
                LengthLimitingTextInputFormatter(3),
              ],
              decoration: const InputDecoration(isDense: true),
              onChanged: (t) {
                final n = int.tryParse(t);
                // Mesmo limite do servidor (0 a 100): divergir mostraria
                // erro sem explicação depois de enviar.
                if (n != null && n >= 0 && n <= 100) onMudou(n);
              },
            ),
          ),
        ),
        const SizedBox(width: 12),
        Expanded(child: Text(rotulo)),
      ],
    ),
  );
}
