import 'package:bolao_mobile/core/api/api_client.dart';
import 'package:bolao_mobile/core/sessao/sessao_store.dart';
import 'package:bolao_mobile/features/auth/data/auth_repository.dart';
import 'package:bolao_mobile/features/auth/data/auth_repository_http.dart';
import 'package:bolao_mobile/features/auth/presentation/cadastro_page.dart';
import 'package:bolao_mobile/features/auth/presentation/sessao_controller.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';

Widget _app(Widget tela) => ProviderScope(child: MaterialApp(home: tela));

/// Cadastro que falha por rede: é o caso em que o formulário **não** pode ser
/// apagado — em conexão ruim, redigitar é o que faz a pessoa desistir do convite.
class _RepoQueCai extends AuthRepositoryHttp {
  _RepoQueCai() : super(ApiClient(SessaoStore()), SessaoStore());

  @override
  Future<Conta> cadastrar({
    required String email,
    required String senha,
    required String nomeExibicao,
  }) async => throw ApiError('sem conexão com o servidor', semConexao: true);
}

Widget _appComFalha() => ProviderScope(
  overrides: [authRepositoryProvider.overrideWithValue(_RepoQueCai())],
  child: const MaterialApp(home: CadastroPage()),
);

void main() {
  group('CadastroPage', () {
    testWidgets('mostra apenas os três campos do caminho crítico', (t) async {
      await t.pumpWidget(_app(const CadastroPage()));

      // Cada campo a mais é participante que não entra — o teste trava o escopo.
      expect(find.byType(TextFormField), findsNWidgets(3));
      expect(find.text('Seu nome no ranking'), findsOneWidget);
      expect(find.text('E-mail'), findsOneWidget);
      expect(find.text('Senha'), findsOneWidget);
    });

    testWidgets('AC-1-11 a tela avisa que não há recuperação de senha', (
      t,
    ) async {
      await t.pumpWidget(_app(const CadastroPage()));

      // Sem serviço de e-mail, esquecer a senha custa a conta. O app precisa
      // dizer isso antes, não depois.
      expect(find.textContaining('não há recuperação'), findsOneWidget);
    });

    testWidgets('AC-1-08 validação por campo antes de chamar a API', (t) async {
      await t.pumpWidget(_app(const CadastroPage()));

      await t.tap(find.text('Criar conta e entrar'));
      await t.pump();

      expect(
        find.text('informe o nome que vai aparecer no ranking'),
        findsOneWidget,
      );
      expect(find.text('informe seu e-mail'), findsOneWidget);
      expect(
        find.text('a senha precisa ter no mínimo 8 caracteres'),
        findsOneWidget,
      );
    });

    testWidgets('AC-1-04 e AC-1-05 e-mail malformado e senha curta são recusados', (t) async {
      await t.pumpWidget(_app(const CadastroPage()));

      await t.enterText(find.byType(TextFormField).at(0), 'Igor');
      await t.enterText(find.byType(TextFormField).at(1), 'nao-e-email');
      await t.enterText(find.byType(TextFormField).at(2), 'curta');
      await t.tap(find.text('Criar conta e entrar'));
      await t.pump();

      expect(find.text('e-mail inválido'), findsOneWidget);
      expect(
        find.text('a senha precisa ter no mínimo 8 caracteres'),
        findsOneWidget,
      );
    });

    testWidgets('preserva o que foi digitado quando a validação falha', (
      t,
    ) async {
      await t.pumpWidget(_app(const CadastroPage()));

      await t.enterText(find.byType(TextFormField).at(0), 'Igor');
      await t.enterText(find.byType(TextFormField).at(1), 'igor@teste.com');
      await t.enterText(find.byType(TextFormField).at(2), 'curta');
      await t.tap(find.text('Criar conta e entrar'));
      await t.pump();

      // Perder o formulário por um erro é o que faz o casual desistir.
      expect(find.text('Igor'), findsOneWidget);
      expect(find.text('igor@teste.com'), findsOneWidget);
    });

    testWidgets('AC-1-09 o mínimo de senha do app é o do servidor', (t) async {
      expect(CadastroPageMinimo.senha, 8);
    });
  });

  group('AC-1-10 falha de rede no cadastro', () {
    testWidgets('mostra o motivo e mantém e-mail e nome na tela', (t) async {
      await t.pumpWidget(_appComFalha());
      await t.pumpAndSettle();

      // Ordem dos campos: nome, e-mail, senha.
      await t.enterText(find.byType(TextFormField).at(0), 'Ana Maria');
      await t.enterText(find.byType(TextFormField).at(1), 'ana@teste.com');
      await t.enterText(find.byType(TextFormField).at(2), 'senhaSegura123');
      await t.pumpAndSettle();

      await t.tap(find.text('Criar conta e entrar'));
      await t.pumpAndSettle();

      expect(find.text('sem conexão com o servidor'), findsOneWidget);
      // O que foi digitado permanece: não há recuperação de senha nesta versão,
      // então perder o formulário aqui é perder o convidado.
      expect(find.text('ana@teste.com'), findsOneWidget);
      expect(find.text('Ana Maria'), findsOneWidget);
      // E o botão volta a funcionar — não fica preso em "enviando".
      final botao = t.widget<FilledButton>(find.byType(FilledButton));
      expect(botao.onPressed, isNotNull);
    });
  });
}

/// Exposto para o teste travar o alinhamento com a regra do backend.
class CadastroPageMinimo {
  static const senha = 8;
}
