import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.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/is_refundable_invoice_response_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/services/logger_service.dart';

abstract class RefundRequestRepo {
  Future<Either<Failure, GenericApiModel<List<RefundableInvoiceItem>>>> getRefundableInvoices({required int projectID});

  Future<Either<Failure, GenericApiModel<RefundableInvoicesDetailsObject>>> getRefundableInvoicesDetails({
    required int invoiceNo,
    required int projectId,
  });

  Future<Either<Failure, GenericApiModel<RefundableAdvancesObject>>> getRefundableAdvances();

  Future<Either<Failure, GenericApiModel<RefundStatusModel>>> getRefundStatus({required String referenceNumber});

  Future<Either<Failure, GenericApiModel<List<RefundInvoiceModel>>>> getRefundInvoices({
    required int refundType,
    required String patientId,
    String invoiceNumberQuery,
  });

  Future<Either<Failure, GenericApiModel<SubmitRefundResponseModel>>> submitRefund({required SubmitRefundRequestModel request});

  Future<Either<Failure, GenericApiModel<IsRefundableInvoiceObject>>> checkIsRefundableInvoice({
    required int invoiceNo,
    required int projectId,
  });
}

class RefundRequestRepoImp implements RefundRequestRepo {
  final ApiClient apiClient;
  final LoggerService loggerService;

  RefundRequestRepoImp({required this.apiClient, required this.loggerService});

  @override
  Future<Either<Failure, GenericApiModel<List<RefundableInvoiceItem>>>> getRefundableInvoices({required int projectID}) async {
    Map<String, dynamic> body = {"ProjectID": projectID};

    try {
      GenericApiModel<List<RefundableInvoiceItem>>? apiResponse;
      Failure? failure;

      await apiClient.post(
        ApiConsts.getRefundableInvoices,
        body: body,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final refundableInvoicesObject = response['RefundableInvoicesObject'];

            if (refundableInvoicesObject != null) {
              final invoiceItemsJson = refundableInvoicesObject['RefundableInvoiceItems'];

              final List<RefundableInvoiceItem> invoicesList = invoiceItemsJson != null
                  ? (invoiceItemsJson as List).map((item) => RefundableInvoiceItem.fromJson(item as Map<String, dynamic>)).toList()
                  : [];

              apiResponse = GenericApiModel<List<RefundableInvoiceItem>>(
                messageStatus: messageStatus,
                statusCode: statusCode,
                errorMessage: errorMessage,
                data: invoicesList,
              );
            } else {
              failure = DataParsingFailure("RefundableInvoicesObject is null");
            }
          } catch (e) {
            loggerService.logError("getRefundableInvoices parsing error: $e");
            failure = DataParsingFailure(e.toString());
          }
        },
      );

      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      loggerService.logError("getRefundableInvoices exception: $e");
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<RefundableInvoicesDetailsObject>>> getRefundableInvoicesDetails({
    required int invoiceNo,
    required int projectId,
  }) async {
    final Map<String, dynamic> body = {
      "InvoiceNo": invoiceNo,
      "ProjectID": projectId,
    };

    try {
      GenericApiModel<RefundableInvoicesDetailsObject>? apiResponse;
      Failure? failure;

      await apiClient.post(
        ApiConsts.getRefundableInvoicesDetails,
        body: body,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final detailsJson = response['RefundableInvoicesDetailsObject'];
            final RefundableInvoicesDetailsObject details = detailsJson != null
                ? RefundableInvoicesDetailsObject.fromJson(detailsJson as Map<String, dynamic>)
                : RefundableInvoicesDetailsObject();

            apiResponse = GenericApiModel<RefundableInvoicesDetailsObject>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: details,
            );
          } catch (e) {
            loggerService.logError("getRefundableInvoicesDetails parsing error: $e");
            failure = DataParsingFailure(e.toString());
          }
        },
      );

      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      loggerService.logError("getRefundableInvoicesDetails exception: $e");
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<RefundableAdvancesObject>>> getRefundableAdvances() async {
    try {
      GenericApiModel<RefundableAdvancesObject>? apiResponse;
      Failure? failure;

      await apiClient.post(
        ApiConsts.getRefundableAdvances,
        body: {},
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final advancesJson = response['RefundableAdvancesObject'];
            final RefundableAdvancesObject advances =
                advancesJson != null ? RefundableAdvancesObject.fromJson(advancesJson as Map<String, dynamic>) : RefundableAdvancesObject();

            apiResponse = GenericApiModel<RefundableAdvancesObject>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: advances,
            );
          } catch (e) {
            loggerService.logError("getRefundableAdvances parsing error: $e");
            failure = DataParsingFailure(e.toString());
          }
        },
      );

      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      loggerService.logError("getRefundableAdvances exception: $e");
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<RefundStatusModel>>> getRefundStatus({required String referenceNumber}) async {
    final Map<String, dynamic> body = {
      "Refund_ReferenceNumber": referenceNumber,
    };

    try {
      GenericApiModel<RefundStatusModel>? apiResponse;
      Failure? failure;

      await apiClient.post(
        ApiConsts.getRefundStatus,
        body: body,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final dataJson = response['Refund_StatusItem'];
            final RefundStatusModel model = dataJson != null ? RefundStatusModel.fromJson(dataJson as Map<String, dynamic>) : RefundStatusModel();

            apiResponse = GenericApiModel<RefundStatusModel>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: model,
            );
          } catch (e) {
            loggerService.logError("getRefundStatus parsing error: $e");
            failure = DataParsingFailure(e.toString());
          }
        },
      );

      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      loggerService.logError("getRefundStatus exception: $e");
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<List<RefundInvoiceModel>>>> getRefundInvoices({
    required int refundType,
    required String patientId,
    String invoiceNumberQuery = "",
  }) async {
    final Map<String, dynamic> body = {
      "Refund_RefundType": refundType,
      "Refund_PatientId": patientId,
      "Refund_InvoiceNumberQuery": invoiceNumberQuery,
    };

    try {
      GenericApiModel<List<RefundInvoiceModel>>? apiResponse;
      Failure? failure;

      await apiClient.post(
        ApiConsts.getRefundInvoices,
        body: body,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final listJson = response['Refund_InvoicesList'];
            final List<RefundInvoiceModel> invoices =
                listJson != null ? (listJson as List).map((item) => RefundInvoiceModel.fromJson(item as Map<String, dynamic>)).toList() : [];

            apiResponse = GenericApiModel<List<RefundInvoiceModel>>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: invoices,
            );
          } catch (e) {
            loggerService.logError("getRefundInvoices parsing error: $e");
            failure = DataParsingFailure(e.toString());
          }
        },
      );

      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      loggerService.logError("getRefundInvoices exception: $e");
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<SubmitRefundResponseModel>>> submitRefund({required SubmitRefundRequestModel request}) async {
    try {
      GenericApiModel<SubmitRefundResponseModel>? apiResponse;
      Failure? failure;

      await apiClient.post(
        ApiConsts.submitRefund,
        body: request.toJson(),
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final model = SubmitRefundResponseModel.fromJson(response as Map<String, dynamic>);
            apiResponse = GenericApiModel<SubmitRefundResponseModel>(
              messageStatus: 1,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: model,
            );
          } catch (e) {
            loggerService.logError("submitRefund parsing error: $e");
            failure = DataParsingFailure(e.toString());
          }
        },
      );

      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      loggerService.logError("submitRefund exception: $e");
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<IsRefundableInvoiceObject>>> checkIsRefundableInvoice({
    required int invoiceNo,
    required int projectId,
  }) async {
    final Map<String, dynamic> body = {
      "InvoiceNo": invoiceNo.toString(),
      "ProjectID": projectId,
    };

    try {
      GenericApiModel<IsRefundableInvoiceObject>? apiResponse;
      Failure? failure;

      await apiClient.post(
        ApiConsts.isRefundableInvoice,
        body: body,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final dataJson = response['IsRefundableInvoiceObject'];
            final IsRefundableInvoiceObject model =
                dataJson != null ? IsRefundableInvoiceObject.fromJson(dataJson as Map<String, dynamic>) : IsRefundableInvoiceObject();

            apiResponse = GenericApiModel<IsRefundableInvoiceObject>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: model,
            );
          } catch (e) {
            loggerService.logError("checkIsRefundableInvoice parsing error: $e");
            failure = DataParsingFailure(e.toString());
          }
        },
      );

      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      loggerService.logError("checkIsRefundableInvoice exception: $e");
      return Left(UnknownFailure(e.toString()));
    }
  }
}
