login method

Future<void> login()

Ensures the user is logged into Firebase and prompts for account selection if multiple accounts are available.

This method provides:

  • Interactive account selection.
  • Support for adding new accounts (--reauth flow).
  • Account switching with automatic session cleanup.
  • Logout functionality.

Implementation

Future<void> login() async {
  print('๐Ÿ” Checking Firebase account...\n');

  try {
    final result = await runWithResult('firebase', ['login:list']);
    final output = result.stdout.toString() + result.stderr.toString();

    final emailRegex =
        RegExp(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}');
    final lines = output.split('\n');
    final allAccounts = <String>[];
    String? currentAccount;

    for (var line in lines) {
      final match = emailRegex.firstMatch(line);
      if (match != null) {
        final email = match.group(0)!;
        if (!allAccounts.contains(email)) {
          allAccounts.add(email);
        }
        // Firebase CLI marks active account with * or (current)
        // Or if it just says "Logged in as email"
        if (line.contains('*') ||
            line.contains('(current)') ||
            line.contains('Logged in as $email')) {
          currentAccount = email;
        }
      }
    }

    // Fallback: If only one account exists, it must be the current one
    if (allAccounts.length == 1 && currentAccount == null) {
      currentAccount = allAccounts.first;
    }

    // If no accounts, need to log in
    if (allAccounts.isEmpty) {
      print('โŒ No Firebase accounts found');
      print('๐Ÿ“ฆ Triggering interactive login...\n');
      await runInteractive('firebase', ['login']);
      return;
    }

    // If we have accounts, ask which one to use
    final prompt = PromptService();
    final options = [
      ...allAccounts,
      '+ Add a new account',
      'โŒ Logout from active account'
    ];

    print('๐Ÿ‘ค Currently logged in accounts:');
    for (int i = 0; i < allAccounts.length; i++) {
      final isCurrent = allAccounts[i] == currentAccount;
      print('  ${i + 1}. ${allAccounts[i]} ${isCurrent ? "โญ๏ธ (active)" : ""}');
    }
    print('');

    final index =
        prompt.select('Select Google account to use for this project', options);

    if (index == allAccounts.length) {
      // Add new account
      print('๐Ÿ“ฆ Adding new account...\n');

      // ๐Ÿ”ฅ CRITICAL: Logout from current to prevent the "login_hint" in URL
      if (currentAccount != null) {
        print('๐Ÿงน Clearing current session hint ($currentAccount)...');
        await run('firebase', ['logout', currentAccount]);
      }

      print('๐Ÿ”„ Opening browser for fresh login...\n');
      await runInteractive('firebase', ['login']);

      // Refresh the check to show the new account list
      print('\n๐Ÿ”„ Refreshing account list...');
      await login();
      return;
    } else if (index == allAccounts.length + 1) {
      // Logout
      if (currentAccount != null) {
        print('๐Ÿšซ Logging out from $currentAccount...\n');
        await run('firebase', ['logout', currentAccount]);
        print('โœ… Logged out successfully');
        await login(); // Refresh
        return;
      } else {
        print('๐Ÿšซ Logging out from all accounts...\n');
        await run('firebase', ['logout']);
        await login();
        return;
      }
    } else {
      final selectedEmail = allAccounts[index];
      if (selectedEmail != currentAccount) {
        print('๐Ÿ”„ Switching to account: $selectedEmail...\n');
        print('โš ๏ธ Switching requires logging out of $currentAccount first.');

        if (currentAccount != null) {
           await run('firebase', ['logout', currentAccount]);
        }

        print('๐Ÿ“ฆ Now please log in to $selectedEmail in the browser...\n');
        await runInteractive('firebase', ['login']);

        await login(); // Re-verify to confirm switch worked
        return;
      } else {
        print('โœ… Using active account: $selectedEmail');
      }
    }

  } catch (e) {
    print('โŒ Firebase account check failed');
    rethrow;
  }
}