import 'dart:async';

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' as dc;
import 'package:krow_domain/krow_domain.dart';

import '../../domain/repositories/tax_forms_repository.dart';
import '../mappers/tax_form_mapper.dart';

class TaxFormsRepositoryImpl implements TaxFormsRepository {
  TaxFormsRepositoryImpl({
    required this.firebaseAuth,
    required this.dataConnect,
  });

  final auth.FirebaseAuth firebaseAuth;
  final dc.ExampleConnector dataConnect;

  /// Helper to get the logged-in staff ID.
  String _getStaffId() {
    final auth.User? user = firebaseAuth.currentUser;
    if (user == null) {
      throw Exception('User not authenticated');
    }
    
    final String? staffId = dc.StaffSessionStore.instance.session?.staff?.id;
    if (staffId == null || staffId.isEmpty) {
      throw Exception('Staff profile is missing or session not initialized.');
    }
    return staffId;
  }

  @override
  Future<List<TaxForm>> getTaxForms() async {
    final String staffId = _getStaffId();
    final QueryResult<dc.GetTaxFormsByStaffIdData, dc.GetTaxFormsByStaffIdVariables>
        result =
        await dataConnect.getTaxFormsByStaffId(staffId: staffId).execute();

    final List<TaxForm> forms = result.data.taxForms.map(TaxFormMapper.fromDataConnect).toList();

    // Check if required forms exist, create if not.
    final Set<TaxFormType> typesPresent = forms.map((TaxForm f) => f.type).toSet();
    bool createdNew = false;

    if (!typesPresent.contains(TaxFormType.i9)) {
      await _createInitialForm(staffId, TaxFormType.i9);
      createdNew = true;
    }
    if (!typesPresent.contains(TaxFormType.w4)) {
      await _createInitialForm(staffId, TaxFormType.w4);
      createdNew = true;
    }

    if (createdNew) {
      final QueryResult<dc.GetTaxFormsByStaffIdData, dc.GetTaxFormsByStaffIdVariables>
          result2 =
          await dataConnect.getTaxFormsByStaffId(staffId: staffId).execute();
      return result2.data.taxForms.map(TaxFormMapper.fromDataConnect).toList();
    }

    return forms;
  }

  Future<void> _createInitialForm(String staffId, TaxFormType type) async {
    await dataConnect
        .createTaxForm(
          staffId: staffId,
          formType:
              dc.TaxFormType.values.byName(TaxFormAdapter.typeToString(type)),
          firstName: '',
          lastName: '',
          socialSN: 0,
          address: '',
          status: dc.TaxFormStatus.NOT_STARTED,
        )
        .execute();
  }

  @override
  Future<void> updateI9Form(I9TaxForm form) async {
    final Map<String, dynamic> data = form.formData;
    final dc.UpdateTaxFormVariablesBuilder builder = dataConnect.updateTaxForm(id: form.id);
    _mapCommonFields(builder, data);
    _mapI9Fields(builder, data);
    await builder.execute();
  }

  @override
  Future<void> submitI9Form(I9TaxForm form) async {
    final Map<String, dynamic> data = form.formData;
    final dc.UpdateTaxFormVariablesBuilder builder = dataConnect.updateTaxForm(id: form.id);
    _mapCommonFields(builder, data);
    _mapI9Fields(builder, data);
    await builder.status(dc.TaxFormStatus.SUBMITTED).execute();
  }

  @override
  Future<void> updateW4Form(W4TaxForm form) async {
    final Map<String, dynamic> data = form.formData;
    final dc.UpdateTaxFormVariablesBuilder builder = dataConnect.updateTaxForm(id: form.id);
    _mapCommonFields(builder, data);
    _mapW4Fields(builder, data);
    await builder.execute();
  }

  @override
  Future<void> submitW4Form(W4TaxForm form) async {
    final Map<String, dynamic> data = form.formData;
    final dc.UpdateTaxFormVariablesBuilder builder = dataConnect.updateTaxForm(id: form.id);
    _mapCommonFields(builder, data);
    _mapW4Fields(builder, data);
    await builder.status(dc.TaxFormStatus.SUBMITTED).execute();
  }

  void _mapCommonFields(dc.UpdateTaxFormVariablesBuilder builder, Map<String, dynamic> data) {
    if (data.containsKey('firstName')) builder.firstName(data['firstName'] as String?);
    if (data.containsKey('lastName')) builder.lastName(data['lastName'] as String?);
    if (data.containsKey('middleInitial')) builder.mInitial(data['middleInitial'] as String?);
    if (data.containsKey('otherLastNames')) builder.oLastName(data['otherLastNames'] as String?);
    if (data.containsKey('dob')) {
      final String dob = data['dob'] as String;
      // Handle both ISO string and MM/dd/yyyy manual entry
      DateTime? date;
      try {
        date = DateTime.parse(dob);
      } catch (_) {
        try {
          // Fallback minimal parse for mm/dd/yyyy
          final List<String> parts = dob.split('/');
          if (parts.length == 3) {
            date = DateTime(
              int.parse(parts[2]), 
              int.parse(parts[0]), 
              int.parse(parts[1]),
            );
          }
        } catch (_) {}
      }
      if (date != null) {
        final int ms = date.millisecondsSinceEpoch;
        final int seconds = (ms / 1000).floor();
        builder.dob(Timestamp(0, seconds));
      }
    }
    if (data.containsKey('ssn') && data['ssn']?.toString().isNotEmpty == true) {
      builder.socialSN(int.tryParse(data['ssn'].toString().replaceAll(RegExp(r'\D'), '')) ?? 0);
    }
    if (data.containsKey('email')) builder.email(data['email'] as String?);
    if (data.containsKey('phone')) builder.phone(data['phone'] as String?);
    if (data.containsKey('address')) builder.address(data['address'] as String?);
    if (data.containsKey('aptNumber')) builder.apt(data['aptNumber'] as String?);
    if (data.containsKey('city')) builder.city(data['city'] as String?);
    if (data.containsKey('state')) builder.state(data['state'] as String?);
    if (data.containsKey('zipCode')) builder.zipCode(data['zipCode'] as String?);
  }

  void _mapI9Fields(dc.UpdateTaxFormVariablesBuilder builder, Map<String, dynamic> data) {
    if (data.containsKey('citizenshipStatus')) {
      final String status = data['citizenshipStatus'] as String;
      // Map string to enum if possible, or handle otherwise.
      // Generated enum: CITIZEN, NONCITIZEN_NATIONAL, PERMANENT_RESIDENT, ALIEN_AUTHORIZED
      try {
        builder.citizen(dc.CitizenshipStatus.values.byName(status.toUpperCase()));
      } catch (_) {}
    }
    if (data.containsKey('uscisNumber')) builder.uscis(data['uscisNumber'] as String?);
    if (data.containsKey('passportNumber')) builder.passportNumber(data['passportNumber'] as String?);
    if (data.containsKey('countryIssuance')) builder.countryIssue(data['countryIssuance'] as String?);
    if (data.containsKey('preparerUsed')) builder.prepartorOrTranslator(data['preparerUsed'] as bool?);
    if (data.containsKey('signature')) builder.signature(data['signature'] as String?);
    // Note: admissionNumber not in builder based on file read
  }

  void _mapW4Fields(dc.UpdateTaxFormVariablesBuilder builder, Map<String, dynamic> data) {
    if (data.containsKey('cityStateZip')) {
       final String csz = data['cityStateZip'] as String;
       // Extremely basic split: City, State Zip
       final List<String> parts = csz.split(',');
       if (parts.length >= 2) {
         builder.city(parts[0].trim());
         final String stateZip = parts[1].trim();
         final List<String> szParts = stateZip.split(' ');
         if (szParts.isNotEmpty) builder.state(szParts[0]);
         if (szParts.length > 1) builder.zipCode(szParts.last);
       }
    }
    if (data.containsKey('filingStatus')) {
      // MARITIAL_STATUS_SINGLE, MARITIAL_STATUS_MARRIED, MARITIAL_STATUS_HEAD
       try {
         final String status = data['filingStatus'] as String;
         // Simple mapping assumptions:
         if (status.contains('single')) builder.marital(dc.MaritalStatus.SINGLE);
         else if (status.contains('married')) builder.marital(dc.MaritalStatus.MARRIED);
         else if (status.contains('head')) builder.marital(dc.MaritalStatus.HEAD);
       } catch (_) {}
    }
    if (data.containsKey('multipleJobs')) builder.multipleJob(data['multipleJobs'] as bool?);
    if (data.containsKey('qualifyingChildren')) builder.childrens(data['qualifyingChildren'] as int?);
    if (data.containsKey('otherDependents')) builder.otherDeps(data['otherDependents'] as int?);
    if (data.containsKey('otherIncome')) {
       builder.otherInconme(double.tryParse(data['otherIncome'].toString()));
    }
    if (data.containsKey('deductions')) {
       builder.deductions(double.tryParse(data['deductions'].toString()));
    }
    if (data.containsKey('extraWithholding')) {
       builder.extraWithholding(double.tryParse(data['extraWithholding'].toString()));
    }
    if (data.containsKey('signature')) builder.signature(data['signature'] as String?);
  }
}

