import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_repo.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/models/lakum_inquiry_information_response_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/models/patient_advance_balance_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/features/refund_request/models/req_models/submit_refund_request_model.dart';
import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/refund_request_list_response_model.dart';
import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/refundable_invoices_response_model.dart';
import 'package:hmg_patient_app_new/features/refund_request/refund_request_repo.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';

class HabibWalletViewModel extends ChangeNotifier {
  HabibWalletRepo habibWalletRepo;
  RefundRequestRepo refundRequestRepo;
  ErrorHandlerService errorHandlerService;

  HabibWalletViewModel({
    required this.habibWalletRepo,
    required this.errorHandlerService,
    required this.refundRequestRepo,
  });

  bool isWalletAmountLoading = false;
  num habibWalletAmount = 0;
  num walletRechargeAmount = 0;
  String notesText = "";
  bool isWalletAmountToBeLoaded = true;

  bool isBottomSheetContentLoading = false;

  // ── Refundable Advances ───────────────────────────────────────────────────
  bool isAdvancesLoading = false;
  double totalAdvancesBalance = 0.0;
  List<RefundableAdvancesItem> refundableAdvancesList = [];
  bool isSubmittingWithdrawal = false;

  bool isSearchedFileNumberDataShown = false;

  int currentIndex = 0;

  List<HospitalsModel> advancePaymentHospitals = [];

  HospitalsModel? selectedHospital;

  String fileNumber = '';
  String depositorName = '';
  String mobileNumber = '';

  num selectedRechargeType = 1;

  List<PatientAdvanceBalanceResponseModel> habibWalletBalanceList = [];

  // ==================== RECHARGE VALIDATION ERROR TRACKING ====================
  // Individual field errors
  String? _amountError;
  String? _hospitalError;

  // Getters for field errors
  String? get amountError => _amountError;

  String? get hospitalError => _hospitalError;

  String yahalaAccountNumber = '';
  bool isLakumAccountInfoLoading = false;
  LakumInquiryInformationResponseModel? lakumAccountInfo;

  // Get all flattened transactions sorted by date descending
  List<PointsDetails> getAllLakumTransactions() {
    if (lakumAccountInfo?.gainedPointsAmountPerYear == null) {
      return [];
    }

    List<PointsDetails> allTransactions = [];

    // Flatten the nested structure
    for (var yearData in lakumAccountInfo!.gainedPointsAmountPerYear!) {
      if (yearData.pointsAmountPerMonth != null) {
        for (var monthData in yearData.pointsAmountPerMonth!) {
          if (monthData.pointsAmountPerday != null) {
            for (var dayData in monthData.pointsAmountPerday!) {
              if (dayData.pointsDetails != null) {
                allTransactions.addAll(dayData.pointsDetails!);
              }
            }
          }
        }
      }
    }

    // Sort by transaction date DESCENDING (latest/most recent transactions first, older transactions last)
    allTransactions.sort((a, b) {
      // Null dates go to the end
      if (a.transactionDate == null && b.transactionDate == null) return 0;
      if (a.transactionDate == null) return 1; // a goes after b
      if (b.transactionDate == null) return -1; // a goes before b

      try {
        DateTime dateA = DateUtil.convertStringToDate(a.transactionDate!);
        DateTime dateB = DateUtil.convertStringToDate(b.transactionDate!);

        // Compare dateB to dateA (not dateA to dateB) for DESCENDING order
        // This puts newer dates (larger values) at the top of the list
        return dateB.compareTo(dateA);
      } catch (e) {
        // If date parsing fails, maintain current order
        return 0;
      }
    });

    return allTransactions;
  }

  // Clear amount error
  void clearAmountError() {
    _amountError = null;
    notifyListeners();
  }

  // Clear hospital error
  void clearHospitalError() {
    _hospitalError = null;
    notifyListeners();
  }

  // Clear all recharge errors
  void clearAllRechargeErrors() {
    _amountError = null;
    _hospitalError = null;
    notifyListeners();
  }

  // ==================== WITHDRAW VALIDATION ERROR TRACKING ====================
  String? _ibanError;
  String? _withdrawDescriptionError;

  String? get ibanError => _ibanError;

  String? get withdrawDescriptionError => _withdrawDescriptionError;

  void clearIbanError() {
    _ibanError = null;
    notifyListeners();
  }

  void clearWithdrawDescriptionError() {
    _withdrawDescriptionError = null;
    notifyListeners();
  }

  bool validateWithdrawForm({required String iban, required String description}) {
    bool isValid = true;
    _ibanError = null;
    _withdrawDescriptionError = null;

    if (iban.trim().isEmpty) {
      _ibanError = LocaleKeys.ibanIsRequired.tr();
      isValid = false;
    } else {
      if (!ValidationUtils.validateIban(iban.trim())) {
        _ibanError = LocaleKeys.invalidIbanFormat.tr();
        isValid = false;
      }
    }

    if (description.trim().isEmpty) {
      _withdrawDescriptionError = LocaleKeys.descriptionIsRequired.tr();
      isValid = false;
    }

    notifyListeners();
    return isValid;
  }

  // Validate recharge form - shows only first error
  bool validateRechargeForm(String amount) {
    // Clear previous errors
    _amountError = null;
    _hospitalError = null;

    // Check if amount is empty
    if (amount.trim().isEmpty) {
      _amountError = "Please enter amount";
      notifyListeners();
      return false;
    }

    // Remove commas and validate amount
    String cleanAmount = amount.replaceAll(',', '');
    final parsedAmount = num.tryParse(cleanAmount);

    if (parsedAmount == null || parsedAmount <= 0) {
      _amountError = "Please enter a valid amount";
      notifyListeners();
      return false;
    }

    // Check if hospital is selected
    if (selectedHospital == null) {
      _hospitalError = "Please select a hospital";
      notifyListeners();
      return false;
    }

    // All validations passed
    notifyListeners();
    return true;
  }

  Future<void> fetchAdvancesForHospital() async {
    isAdvancesLoading = true;
    totalAdvancesBalance = 0.0;
    refundableAdvancesList = [];
    notifyListeners();

    final result = await refundRequestRepo.getRefundableAdvances();
    result.fold(
      (failure) {
        isAdvancesLoading = false;
        notifyListeners();
        errorHandlerService.handleError(failure: failure);
      },
      (apiResponse) {
        isAdvancesLoading = false;
        if (apiResponse.data != null) {
          refundableAdvancesList = apiResponse.data!.refundableAdvancesItems;
          totalAdvancesBalance = refundableAdvancesList.fold(0.0, (sum, item) => sum + (item.balanceAmount ?? 0.0));
        }
        notifyListeners();
      },
    );
  }

  /// Converts a WCF /Date(ms+timezone)/ string to "YYYY-MM-DD" format expected by the API.
  String _formatAdvanceDate(String? rawDate) {
    if (rawDate == null || rawDate.isEmpty) return '';
    try {
      final date = DateUtil.convertStringToDate(rawDate);
      return DateFormat('yyyy-MM-dd').format(date);
    } catch (_) {
      return rawDate;
    }
  }

  Future<void> submitWalletWithdrawalRequest({
    required String iban,
    required String remarks,
    required String patientName,
    required String patientId,
    required String patientMobileNumber,
    required String patientNationalId,
    required int projectId,
    required String projectName,
    Function(SubmitRefundResponseModel)? onSuccess,
    Function(String)? onError,
  }) async {
    isSubmittingWithdrawal = true;
    notifyListeners();

    final advances = refundableAdvancesList
        .map((a) => SubmitRefundAdvanceItem(
              advanceNo: (a.advanceNo ?? 0).toString(),
              paidAmount: a.paidAmount ?? 0.0,
              balanceAmount: a.balanceAmount ?? 0.0,
              advanceDate: a.advanceDate ?? "",
              // advanceDate: _formatAdvanceDate(a.advanceDate),
            ))
        .toList();

    final request = SubmitRefundRequestModel(
      projectId: projectId,
      isRefundFastTrack: true,
      // in case of wallet refund, skip ITG approval
      refundType: '2',
      // wallet withdrawal
      refundProject: projectName,
      refundProjectId: projectId,
      refundPatientId: patientId,
      patientMobileNumber: patientMobileNumber,
      refundPatientName: patientName,
      refundNationalId: patientNationalId,
      refundInvoiceNo: '',
      refundAppointmentNo: '',
      refundDoctorId: 0,
      refundDoctorName: '',
      refundClinicId: 0,
      refundClinicName: '',
      refundDestination: '2',
      // only bank transfer
      refundIban: iban,
      refundRemarks: remarks,
      refundTotalAmount: totalAdvancesBalance,
      refundProceduresList: const [],
      refundAdvancesList: advances,
    );

    final result = await refundRequestRepo.submitRefund(request: request);
    result.fold(
      (failure) {
        isSubmittingWithdrawal = false;
        notifyListeners();
        if (onError != null) {
          onError(failure.message);
        } else {
          errorHandlerService.handleError(failure: failure);
        }
      },
      (apiResponse) {
        isSubmittingWithdrawal = false;
        notifyListeners();
        if (apiResponse.data != null) {
          if (onSuccess != null) onSuccess(apiResponse.data!);
        } else {
          if (onError != null) {
            onError(apiResponse.errorMessage ?? LocaleKeys.failed.tr());
          }
        }
      },
    );
  }

  initHabibWalletProvider() {
    if (isWalletAmountToBeLoaded) {
      isWalletAmountLoading = true;
      habibWalletAmount = 0;
      isLakumAccountInfoLoading = true;
      yahalaAccountNumber = "";
    }
    isBottomSheetContentLoading = false;
    walletRechargeAmount = 0;
    selectedRechargeType = 1;
    advancePaymentHospitals.clear();
    selectedHospital = null;
    fileNumber = '';
    depositorName = '';
    mobileNumber = '';
    notifyListeners();
  }

  setSelectedRechargeType(num type) {
    selectedRechargeType = type;
    notifyListeners();
  }

  setSelectedHospital(HospitalsModel hospital) {
    selectedHospital = hospital;
    clearHospitalError();
    notifyListeners();
  }

  /// Resets all state related to the wallet withdrawal form.
  /// Pass [silent] = true when calling from dispose() to avoid notifyListeners
  /// while the widget tree is locked.
  void resetWithdrawForm({bool silent = false}) {
    selectedHospital = null;
    totalAdvancesBalance = 0.0;
    refundableAdvancesList = [];
    isAdvancesLoading = false;
    isSubmittingWithdrawal = false;
    _ibanError = null;
    _withdrawDescriptionError = null;
    if (!silent) notifyListeners();
  }

  setWalletRechargeAmount(num amount) {
    walletRechargeAmount = amount;
    notifyListeners();
  }

  setNotesText(String notes) {
    notesText = notes;
    notifyListeners();
  }

  setDepositorDetails(String fileNum, String depositor, String mobile) {
    fileNumber = fileNum;
    depositorName = depositor;
    mobileNumber = mobile;
    notifyListeners();
  }

  setCurrentIndex(int index) {
    currentIndex = index;
    notifyListeners();
  }

  setYahalaAccountNumber(String accountNumber) {
    yahalaAccountNumber = accountNumber;
    notifyListeners();
  }

  setIsWalletAmountToBeLoaded(bool value) {
    isWalletAmountToBeLoaded = value;
    notifyListeners();
  }

  String getSelectedRechargeTypeValue() {
    switch (selectedRechargeType) {
      case 1:
        return LocaleKeys.myAccount.tr();
      case 2:
        return LocaleKeys.family.tr();
      case 3:
        return LocaleKeys.otherAccount.tr();
      default:
        return LocaleKeys.myAccount.tr();
    }
  }

  Future<void> getPatientBalanceAmount({Function(dynamic)? onSuccess, Function(String)? onError}) async {
    if (!isWalletAmountToBeLoaded) {
      return;
    }
    habibWalletBalanceList.clear();
    isWalletAmountLoading = true;
    notifyListeners();

    final result = await habibWalletRepo.getPatientBalanceAmount();

    result.fold(
      (failure) async => await errorHandlerService.handleError(failure: failure),
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
          // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
        } else if (apiResponse.messageStatus == 1) {
          habibWalletBalanceList = apiResponse.data;
          habibWalletAmount = habibWalletBalanceList.first.totalAmount ?? 0.0;

          habibWalletBalanceList.sort((a, b) => b.patientAdvanceBalanceAmount!.compareTo(a.patientAdvanceBalanceAmount!));

          habibWalletBalanceList.removeWhere((element) => element.patientAdvanceBalanceAmount == 0);

          isWalletAmountLoading = false;
          isWalletAmountToBeLoaded = false;
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse);
          }
        }
      },
    );
  }

  Future<void> getProjectsList() async {
    advancePaymentHospitals.clear();
    notifyListeners();
    final result = await habibWalletRepo.getProjectList();

    result.fold(
      (failure) async => await errorHandlerService.handleError(failure: failure),
      (apiResponse) async {
        if (apiResponse.messageStatus == 2) {
          // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
        } else if (apiResponse.messageStatus == 1) {
          advancePaymentHospitals = apiResponse.data!;
          notifyListeners();
        }
      },
    );
  }

  Future<void> HISCreateAdvancePayment(
      {required String paymentMethodName,
      required num paidAmount,
      required String paymentReference,
      required String patientID,
      required int projectID,
      required String depositorName,
      Function(dynamic)? onSuccess,
      Function(String)? onError}) async {
    final result = await habibWalletRepo.HISCreateAdvancePayment(
        paymentMethodName: paymentMethodName, paidAmount: paidAmount, paymentReference: paymentReference, patientID: patientID, projectID: projectID, depositorName: depositorName);

    result.fold(
      // (failure) async => await errorHandlerService.handleError(failure: failure),
      (failure) async {
        if (onError != null) {
          onError(failure.message);
        }
      },
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
          // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
        } else if (apiResponse.messageStatus == 1) {
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse);
          }
        }
      },
    );
  }

  Future<void> addAdvanceNumberRequest({required String advanceNumber, required String paymentReference, Function(dynamic)? onSuccess, Function(String)? onError}) async {
    final result = await habibWalletRepo.addAdvanceNumberRequest(advanceNumber: advanceNumber, paymentReference: paymentReference);

    result.fold(
      (failure) async => await errorHandlerService.handleError(failure: failure),
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
          // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
        } else if (apiResponse.messageStatus == 1) {
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse);
          }
        }
      },
    );
  }

  Future<void> getPatientInfoByPatientID({required String patientID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
    isBottomSheetContentLoading = true;
    notifyListeners();
    final result = await habibWalletRepo.getPatientInfoByPatientID(patientID: patientID);

    result.fold(
      (failure) async {
        isBottomSheetContentLoading = false;
        notifyListeners();
        await errorHandlerService.handleError(failure: failure);
      },
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
          // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
        } else if (apiResponse.messageStatus == 1) {
          isBottomSheetContentLoading = false;
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse);
          }
        }
      },
    );
  }

  Future<void> getLakumAccountInformation({Function(dynamic)? onSuccess, Function(String)? onError}) async {
    if (!isWalletAmountToBeLoaded) {
      return;
    }

    isLakumAccountInfoLoading = true;
    lakumAccountInfo = LakumInquiryInformationResponseModel();
    notifyListeners();

    final result = await habibWalletRepo.getLakumAccountInformation(identificationNumber: getIt.get<AppState>().getAuthenticatedUser()!.patientIdentificationNo ?? "");

    result.fold(
      // (failure) async => await errorHandlerService.handleError(failure: failure),
      (failure) async {
        yahalaAccountNumber = "0";
        isLakumAccountInfoLoading = false;
        notifyListeners(); // 675534
      },
      (apiResponse) async {
        if (apiResponse.messageStatus == 2) {
          yahalaAccountNumber = "0";
          isLakumAccountInfoLoading = false;
          notifyListeners();
        } else if (apiResponse.messageStatus == 1) {
          if (apiResponse.data["YahalaAccountNo"] == 0 || apiResponse.data["YahalaAccountNo"] == "0") {
            yahalaAccountNumber = "0";
          } else {
            yahalaAccountNumber = apiResponse.data["YahalaAccountNo"].toString();

            final lakumAccountResult = await habibWalletRepo.getLakumAccountInquiryInformation(lakumAccountNumber: yahalaAccountNumber);
            lakumAccountResult.fold(
              (failure) async => await errorHandlerService.handleError(failure: failure),
              (lakumApiResponse) async {
                if (lakumApiResponse.messageStatus == 2) {
                  lakumAccountInfo = LakumInquiryInformationResponseModel();
                } else if (lakumApiResponse.messageStatus == 1) {
                  lakumAccountInfo = LakumInquiryInformationResponseModel.fromJson(lakumApiResponse.data["LakumInquiryInformationObjVersion"]);
                }
              },
            );
          }
          isLakumAccountInfoLoading = false;
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse);
          }
        }
      },
    );
  }
}
