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

import '../../../core/api/api_client.dart';
import '../data/convite_store.dart';
import 'rodada_page.dart';

final conviteStoreProvider = Provider<ConviteStore>((_) => ConviteStore());

/// Convite do bolão.
///
/// A regra que molda esta tela: **gerar um convite revoga o anterior**. Antes,
/// abrir a tela já gerava — o admin que tocasse duas vezes matava o link que
/// tinha acabado de mandar no grupo, sem nunca saber por quê. Aqui a geração é
/// uma ação explícita, e o código já gerado neste device é mostrado de novo.
class ConviteDialog extends ConsumerStatefulWidget {
  const ConviteDialog({required this.poolId, super.key});

  final String poolId;

  @override
  ConsumerState<ConviteDialog> createState() => _ConviteDialogState();
}

class _ConviteDialogState extends ConsumerState<ConviteDialog> {
  String? _token;
  String? _erro;
  bool _carregando = true;
  bool _trabalhando = false;

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

  Future<void> _carregarLocal() async {
    final salvo = await ref.read(conviteStoreProvider).ler(widget.poolId);
    if (!mounted) return;
    setState(() {
      _token = salvo;
      _carregando = false;
    });
  }

  Future<void> _gerar() async {
    setState(() {
      _trabalhando = true;
      _erro = null;
    });
    try {
      final convite = await ref
          .read(boloesRepositoryProvider)
          .gerarConvite(widget.poolId);
      await ref.read(conviteStoreProvider).salvar(widget.poolId, convite.token);
      if (!mounted) return;
      setState(() => _token = convite.token);
    } on ApiError catch (e) {
      // Bolão já começado ou encerrado tem motivo próprio vindo do servidor.
      if (mounted) setState(() => _erro = e.mensagem);
    } finally {
      if (mounted) setState(() => _trabalhando = false);
    }
  }

  Future<void> _confirmarNovo() async {
    final ok = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Gerar um código novo?'),
        content: const Text(
          'O código atual para de funcionar na hora. Quem já recebeu o antigo '
          'e ainda não entrou vai precisar do novo.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('Cancelar'),
          ),
          FilledButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: const Text('Gerar novo'),
          ),
        ],
      ),
    );
    if (ok == true) await _gerar();
  }

  Future<void> _invalidar() async {
    final ok = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Invalidar o convite?'),
        content: const Text(
          'Ninguém mais entra com este código. Você pode gerar outro depois.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('Cancelar'),
          ),
          FilledButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: const Text('Invalidar'),
          ),
        ],
      ),
    );
    if (ok != true) return;

    setState(() => _trabalhando = true);
    try {
      await ref.read(boloesRepositoryProvider).invalidarConvite(widget.poolId);
      await ref.read(conviteStoreProvider).limpar(widget.poolId);
      if (!mounted) return;
      setState(() => _token = null);
    } on ApiError catch (e) {
      if (mounted) setState(() => _erro = e.mensagem);
    } finally {
      if (mounted) setState(() => _trabalhando = false);
    }
  }

  /// Compartilhamento pelos apps do device. É por onde o convite realmente
  /// circula: o admin manda no grupo do WhatsApp, não copia e cola.
  Future<void> _compartilhar() async {
    await SharePlus.instance.share(
      ShareParams(
        // Link primeiro: com o app instalado, um toque resolve. O código vai
        // logo abaixo porque link de esquema próprio não abre nada em quem não
        // tem o app — e aí colar o código é o caminho que sobra.
        text:
            'Entra no meu bolão! Toque no link:\n\n'
            '$linkDoConvite\n\n'
            'Se o link não abrir, instale o app do Bolão, toque em "entrar por '
            'convite" e cole este código:\n\n${_token!}\n\n'
            'Vale por 1 dia e fecha quando o primeiro jogo começar.',
        subject: 'Convite do bolão',
      ),
    );
  }

  /// Link do convite. `bolao://bolao.app/convite/<token>` — host fixo e o
  /// "convite" no caminho, porque com esquema próprio o Flutter recebe só o
  /// `path` da URI.
  String get linkDoConvite =>
      'bolao://bolao.app/convite/${Uri.encodeComponent(_token!)}';

  Future<void> _copiar() async {
    await Clipboard.setData(ClipboardData(text: _token!));
    if (!mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Código copiado — cole no grupo')),
    );
  }

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

    return AlertDialog(
      title: const Text('Convite do bolão'),
      content: _carregando
          ? const Center(
              child: Padding(
                padding: EdgeInsets.all(16),
                child: CircularProgressIndicator(),
              ),
            )
          : Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                if (_token == null)
                  const Text(
                    'Nenhum código ativo neste aparelho. Gere um para chamar a '
                    'galera.',
                  )
                else ...[
                  const Text('Mande este código para a galera:'),
                  const SizedBox(height: 12),
                  SelectableText(
                    _token!,
                    style: const TextStyle(
                      fontFamily: 'monospace',
                      fontSize: 12,
                    ),
                  ),
                  const SizedBox(height: 12),
                  const Text(
                    'Vale por 1 dia. A entrada fecha quando o primeiro jogo '
                    'começar.',
                    style: TextStyle(fontSize: 12),
                  ),
                ],
                if (_erro != null) ...[
                  const SizedBox(height: 12),
                  Text(
                    _erro!,
                    style: TextStyle(color: cores.error, fontSize: 12),
                  ),
                ],
              ],
            ),
      actions: _carregando
          ? null
          : [
              if (_token != null) ...[
                TextButton(
                  onPressed: _trabalhando ? null : _invalidar,
                  child: const Text('Invalidar'),
                ),
                TextButton(
                  onPressed: _trabalhando ? null : _confirmarNovo,
                  child: const Text('Gerar novo'),
                ),
                TextButton(
                  onPressed: _trabalhando ? null : _copiar,
                  child: const Text('Copiar'),
                ),
                FilledButton(
                  onPressed: _trabalhando ? null : _compartilhar,
                  child: const Text('Compartilhar'),
                ),
              ] else
                FilledButton(
                  onPressed: _trabalhando ? null : _gerar,
                  child: const Text('Gerar código'),
                ),
              TextButton(
                onPressed: () => Navigator.of(context).pop(),
                child: const Text('Fechar'),
              ),
            ],
    );
  }
}
