part of 'app_test.dart';

class AuthenticationTest {
  static Future<void> signIn() async {
    patrolWidgetTest(
      'Sign-In with fuzzed emails',
      (PatrolTester tester) async {
        $ = tester;
        $.tester
            .printToConsole('Authentication Test - Sign-In with fuzzed emails');
        final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);

        final Fuzzer fuzzer = Fuzzer(
          configs: [
            FuzzConfig(
              label: 'username',
              type: AcceptedTypes.string,
              minLength: 5,
              maxLength: 10,
            ),
            FuzzConfig(
              label: 'domain',
              type: AcceptedTypes.string,
              minLength: 5,
              maxLength: 10,
            ),
            FuzzConfig(
              label: 'password',
              type: AcceptedTypes.string,
              minLength: 5,
              maxLength: 10,
            ),
          ],
          iterations: 2,
        );
        Map<String, String> concat(
            String username, String domain, String password) {
          return {
            'emailTextFormField': '${username}@${domain}.test',
            'passwordTextFormField': password,
          };
        }

        final credentials = fuzzer.fuzz(concat);

        await _unlogged();
        await $.pumpWidgetAndSettle(const App());
        await _navigateToSignIn($);

        for (var credential in credentials) {
          print('Função: ${credential.functionName}');
          print('Entradas: ${credential.inputs}');
          print('Saída: ${credential.output}');
          print('Mensagem: ${credential.message}');
          print('---');

          await _auth(credential.output, $, throwsException);
        }
      },
    );

    patrolWidgetTest(
      'Sign-In with email_app@exemplo.com',
      (PatrolTester tester) async {
        $ = tester;
        $.tester.printToConsole(
            'Authentication Test - Sign-In with email_app@exemplo.com');

        final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
        final Map<String, String> credentials = {
          'emailTextFormField': 'email_app@exemplo.com',
          'passwordTextFormField': '12345678',
        };

        await _unlogged();
        await $.pumpWidgetAndSettle(const App());
        await _navigateToSignIn($);
        await _auth(credentials, $, throwsException);
      },
    );
  }

  static Future<void> signUp() async {
    patrolWidgetTest(
      'Sign Up - credenciais já registradas',
      (PatrolTester tester) async {
        $ = tester;
        $.tester.printToConsole(
            'Authentication Test - Sign-Up: credenciais já registradas');

        final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
        final Map<String, String> credentials = {
          'nameTextFormField': 'app',
          'emailTextFormField': 'email_app@exemplo.com',
          'passwordTextFormField': '12345678',
        };
        await _unlogged();
        await $.pumpWidgetAndSettle(const App());
        await _navigateToSignUp($);
        await _auth(credentials, $, throwsException);
        await Future.delayed(const Duration(milliseconds: 500));
      },
    );

    patrolWidgetTest(
      'Sign Up - credenciais novas',
      (PatrolTester tester) async {
        $ = tester;
        $.tester
            .printToConsole('Authentication Test - Sign-Up: credenciais novas');

        final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);

        final Fuzzer fuzzer = Fuzzer(
          configs: [
            FuzzConfig(
              label: 'name',
              type: AcceptedTypes.string,
              minLength: 5,
              maxLength: 10,
            ),
            FuzzConfig(
              label: 'username',
              type: AcceptedTypes.string,
              minLength: 5,
              maxLength: 10,
            ),
            FuzzConfig(
              label: 'domain',
              type: AcceptedTypes.string,
              minLength: 5,
              maxLength: 10,
            ),
            FuzzConfig(
              label: 'password',
              type: AcceptedTypes.string,
              minLength: 8,
              maxLength: 10,
            ),
          ],
          iterations: 2,
        );
        Map<String, String> concat(
            String name, String username, String domain, String password) {
          return {
            'nameTextFormField': name,
            'emailTextFormField': '${username}@${domain}.test',
            'passwordTextFormField': password,
          };
        }

        final credentials = fuzzer.fuzz(concat);

        await _unlogged();

        await $.pumpWidgetAndSettle(const App());

        for (var credential in credentials) {
          print('Função: ${credential.functionName}');
          print('Entradas: ${credential.inputs}');
          print('Saída: ${credential.output}');
          print('Mensagem: ${credential.message}');
          print('---');

          await _navigateToSignUp($);
          await _auth(credential.output, $, throwsException);
        }
      },
    );
  }

  static Future<void> signOut() async {
    patrolWidgetTest(
      'Deslogar da Conta',
      (PatrolTester tester) async {
        $ = tester;
        $.tester.printToConsole(
            'Authentication Test - Sign-Out: Deslogar da Conta');

        await _loggedWithMultiLocalsAccount();
        await $.pumpWidget(const App());

        await $.waitUntilVisible($(MenuStaggeredView));

        await $(Icons.menu_rounded).waitUntilVisible().tap();

        await $.waitUntilVisible($(MenuListView));

        await $(Icons.exit_to_app)
            .waitUntilVisible()
            .tap(settlePolicy: SettlePolicy.trySettle);

        await Future.delayed(const Duration(milliseconds: 500));
      },
    );
  }

  static void recovery() async {
    patrol('Open url in the app', ($) async {
      await _loggedWithMultiLocalsAccount();
      await $.pumpWidget(const App());

      await $.waitUntilVisible($(MenuStaggeredView));

      // await $.native.pressHome();
      // final String browserId = 'com.android.chrome';
      // await $.native.openApp(appId: browserId);
      await $.native.openUrl(//
          'https://freaccess.com.br/freaccess/alterarSenha.php?email=freaccesshub@gmail.com&token=67939240e12c31.10412525');

      await $.pumpAndSettle();
      Future.delayed(Duration(seconds: 3));
      await $.pump(Duration(seconds: 3));
      await $.pumpAndSettle();
      final PatrolFinder forgotPassword =
          await $(#ForgotPasswordScreen).waitUntilVisible();
      expect(forgotPassword, findsOneWidget);
    });
  }
}

Future<void> _auth(
  Map<String, String> credentials,
  PatrolTester $,
  PatrolFinder throwsException,
) async {
  await _enterCredentials(credentials, $);
  await _submit('SubmitButtonWidget', $, throwsException);
}

Future<void> _enterCredentials(
  Map<String, String> credentials,
  PatrolTester $,
) async {
  for (var entry in credentials.entries) {
    await $(ValueKey(entry.key)) //
        .waitUntilVisible()
        .enterText(entry.value);
    await $.pumpAndSettle();
  }
}

Future<void> _submit(
    String key, PatrolTester $, PatrolFinder throwsException) async {
  await $(ValueKey(key)) //
      .waitUntilVisible()
      .tap();
  await $.pump(Duration(milliseconds: 1000));
  if ($(ValueKey('ThrowExceptionWidget')).exists) {
    // expect(throwsException, findsOneWidget);
    await $(ValueKey('ThrowExceptionWidget')) //
        .waitUntilVisible()
        .tap();
  } else {
    _navigateBackUsingSystemGesture();
  }
}

String _generateRandomString(int length) {
  const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
  final rand = Random();
  return List.generate(length, (index) => chars[rand.nextInt(chars.length)])
      .join();
}
