import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:firebase_data_connect/firebase_data_connect.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:krow_domain/krow_domain.dart';

import '../../domain/repositories/bank_account_repository.dart';

/// Implementation of [BankAccountRepository].
class BankAccountRepositoryImpl implements BankAccountRepository {
  const BankAccountRepositoryImpl({
    required this.dataConnect,
    required this.firebaseAuth,
  });

  final ExampleConnector dataConnect;
  final auth.FirebaseAuth firebaseAuth;

  @override
  Future<List<BankAccount>> getAccounts() async {
    final auth.User? user = firebaseAuth.currentUser;
    if (user == null) throw Exception('User not authenticated');
    final String? staffId = StaffSessionStore.instance.session?.staff?.id;
    if (staffId == null || staffId.isEmpty) {
      print('BankAccount getAccounts: missing staffId userId=${user.uid} session=${StaffSessionStore.instance.session}');
      throw Exception('Staff profile is missing.');
    }

    final QueryResult<GetAccountsByOwnerIdData, GetAccountsByOwnerIdVariables>
        result = await dataConnect
            .getAccountsByOwnerId(ownerId: staffId)
            .execute();
    
    return result.data.accounts.map((GetAccountsByOwnerIdAccounts account) {
      return BankAccount(
        id: account.id,
        userId: account.ownerId,
        bankName: account.bank,
        accountNumber: account.accountNumber ?? '',
        last4: account.last4,
        accountName: '', // Not returned by API
        sortCode: account.routeNumber,
        type: _mapAccountType(account.type),
        isPrimary: account.isPrimary ?? false,
      );
    }).toList();
  }

  @override
  Future<void> addAccount(BankAccount account) async {
    final auth.User? user = firebaseAuth.currentUser;
    if (user == null) throw Exception('User not authenticated');
    final String? staffId = StaffSessionStore.instance.session?.staff?.id;
    if (staffId == null || staffId.isEmpty) {
      print('BankAccount addAccount: missing staffId userId=${user.uid} session=${StaffSessionStore.instance.session}');
      throw Exception('Staff profile is missing.');
    }

    final QueryResult<GetAccountsByOwnerIdData, GetAccountsByOwnerIdVariables>
        existingAccounts = await dataConnect
            .getAccountsByOwnerId(ownerId: staffId)
            .execute();
    final bool hasAccounts = existingAccounts.data.accounts.isNotEmpty;
    final bool isPrimary = !hasAccounts;

    await dataConnect.createAccount(
      bank: account.bankName,
      type: _mapDomainType(account.type),
      last4: _safeLast4(account.last4, account.accountNumber),
      ownerId: staffId,
    ).isPrimary(isPrimary).accountNumber(account.accountNumber).routeNumber(account.sortCode).execute();
  }

  BankAccountType _mapAccountType(EnumValue<AccountType> type) {
    if (type is Known<AccountType>) {
      switch (type.value) {
        case AccountType.CHECKING:
          return BankAccountType.checking;
        case AccountType.SAVINGS:
          return BankAccountType.savings;
      }
    }
    return BankAccountType.other;
  }

  AccountType _mapDomainType(BankAccountType type) {
    switch (type) {
      case BankAccountType.checking:
        return AccountType.CHECKING;
      case BankAccountType.savings:
        return AccountType.SAVINGS;
      default:
        return AccountType.CHECKING; // Default fallback
    }
  }

  String _safeLast4(String? last4, String accountNumber) {
    if (last4 != null && last4.isNotEmpty) {
      return last4;
    }
    if (accountNumber.isEmpty) {
      return '';
    }
    return accountNumber.length > 4
        ? accountNumber.substring(accountNumber.length - 4)
        : accountNumber;
  }
}
