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/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_allergies_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_medical_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_vaccine_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';

import '../authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'models/family_file_response_model.dart';

abstract class MedicalFileRepo {
  Future<Either<Failure, GenericApiModel<List<PatientVaccineResponseModel>>>> getPatientVaccinesList();

  Future<Either<Failure, GenericApiModel<List<PatientSickLeavesResponseModel>>>> getPatientSickLeavesList();

  Future<Either<Failure, GenericApiModel<dynamic>>> getPatientSickLeavePDF(PatientSickLeavesResponseModel patientSickLeavesResponseModel, AuthenticatedUser authenticatedUser);

  Future<Either<Failure, GenericApiModel<List<PatientMedicalReportResponseModel>>>> getPatientMedicalReportsList();

  Future<Either<Failure, GenericApiModel<dynamic>>> getPatientMedicalReportPDF(PatientMedicalReportResponseModel patientMedicalReportResponseModel, AuthenticatedUser authenticatedUser);

  Future<Either<Failure, GenericApiModel<List<FamilyFileResponseModelLists>>>> getPatientFamilyFiles(int? status, int patientId);

  Future<Either<Failure, GenericApiModel<List<FamilyFileResponseModelLists>>>> getAllPendingRecordsByResponseId({required Map<String, dynamic> request});

  Future<Either<Failure, GenericApiModel<dynamic>>> addFamilyFile({required dynamic request});

  Future<Either<Failure, GenericApiModel<List<PatientAppointmentHistoryResponseModel>>>> getPatientAppointmentsForMedicalReport();

  Future<Either<Failure, GenericApiModel<dynamic>>> insertRequestForMedicalReport({required PatientAppointmentHistoryResponseModel appointmentHistoryResponseModel});

  Future<Either<Failure, GenericApiModel<dynamic>>> removeFamilyFile({required int? id});

  Future<Either<Failure, GenericApiModel<dynamic>>> acceptRejectFamilyFile({required int? id, required int? status});

  Future<Either<Failure, GenericApiModel<List<GetAllergiesResponseModel>>>> getPatientAllergiesList({Function(dynamic)? onSuccess, Function(String)? onError});
}

class MedicalFileRepoImp implements MedicalFileRepo {
  final ApiClient apiClient;
  final LoggerService loggerService;

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

  @override
  Future<Either<Failure, GenericApiModel<List<PatientVaccineResponseModel>>>> getPatientVaccinesList() async {
    Map<String, dynamic> mapDevice = {"To": "0", "From": "0"};

    try {
      GenericApiModel<List<PatientVaccineResponseModel>>? apiResponse;
      Failure? failure;
      await apiClient.post(
        GET_VACCINES,
        body: mapDevice,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final list = response['List_DoneVaccines'];
            // if (list == null || list.isEmpty) {
            //   throw Exception("lab list is empty");
            // }

            final vaccinesList = list.map((item) => PatientVaccineResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientVaccineResponseModel>();

            apiResponse = GenericApiModel<List<PatientVaccineResponseModel>>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: vaccinesList,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<List<PatientSickLeavesResponseModel>>>> getPatientSickLeavesList() async {
    Map<String, dynamic> mapDevice = {};

    try {
      GenericApiModel<List<PatientSickLeavesResponseModel>>? apiResponse;
      Failure? failure;
      await apiClient.post(
        GET_PATIENT_SICK_LEAVE_STATUS,
        body: mapDevice,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final list = response['List_SickLeave'];
            // if (list == null || list.isEmpty) {
            //   throw Exception("lab list is empty");
            // }

            final sickLeavesList = list.map((item) => PatientSickLeavesResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientSickLeavesResponseModel>();

            apiResponse = GenericApiModel<List<PatientSickLeavesResponseModel>>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: sickLeavesList,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel>> getPatientSickLeavePDF(PatientSickLeavesResponseModel patientSickLeavesResponseModel, AuthenticatedUser authenticatedUser) async {
    Map<String, dynamic> mapDevice = {
      "RequestNo": patientSickLeavesResponseModel.requestNo,
      "To": authenticatedUser.emailAddress,
      "DateofBirth": authenticatedUser.dateofBirth,
      "PatientIditificationNum": authenticatedUser.patientIdentificationNo,
      "PatientMobileNumber": authenticatedUser.mobileNumber,
      "PatientName": "${authenticatedUser.firstName!} ${authenticatedUser.lastName!}",
      "ProjectName": patientSickLeavesResponseModel.projectName,
      "DoctorName": patientSickLeavesResponseModel.doctorName,
      "ProjectID": patientSickLeavesResponseModel.projectID,
      "SetupID": patientSickLeavesResponseModel.setupID,
      "IsDownload": true,
    };

    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        SendSickLeaveEmail,
        body: mapDevice,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            // final list = response['List_SickLeave'];
            // if (list == null || list.isEmpty) {
            //   throw Exception("lab list is empty");
            // }

            // final vaccinesList = list.map((item) => PatientSickLeavesResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientSickLeavesResponseModel>();

            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: response["Base64Data"],
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<List<PatientMedicalReportResponseModel>>>> getPatientMedicalReportsList() async {
    Map<String, dynamic> mapDevice = {
      "IsReport": true,
      "EncounterType": 1,
      "RequestType": 1,
    };

    try {
      GenericApiModel<List<PatientMedicalReportResponseModel>>? apiResponse;
      Failure? failure;
      await apiClient.post(
        REPORTS,
        body: mapDevice,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final list = response['GetPatientMedicalStatus'];
            // if (list == null || list.isEmpty) {
            //   throw Exception("lab list is empty");
            // }

            final vaccinesList = list.map((item) => PatientMedicalReportResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientMedicalReportResponseModel>();

            apiResponse = GenericApiModel<List<PatientMedicalReportResponseModel>>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: vaccinesList,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel>> getPatientMedicalReportPDF(PatientMedicalReportResponseModel patientMedicalReportResponseModel, AuthenticatedUser authenticatedUser) async {
    Map<String, dynamic> mapDevice = {
      "SetupID": patientMedicalReportResponseModel.setupId,
      "PrintDate": patientMedicalReportResponseModel.requestDate!,
      "ProcedureID": "05005009",
      "Reporttype": "MEDICAL REPORT",
      "stamp": patientMedicalReportResponseModel.requestDate!,
      "To": authenticatedUser.emailAddress,
      "DateofBirth": authenticatedUser.dateofBirth,
      "PatientIditificationNum": authenticatedUser.patientIdentificationNo,
      "PatientMobileNumber": authenticatedUser.mobileNumber,
      "PatientName": "${authenticatedUser.firstName!} ${authenticatedUser.lastName!}",
      "ProjectName": patientMedicalReportResponseModel.projectName,
      "ClinicName": patientMedicalReportResponseModel.clinicDescription,
      "ProjectID": patientMedicalReportResponseModel.projectID,
      "InvoiceNo": Utils.isVidaPlusProject(patientMedicalReportResponseModel.projectID!) ? patientMedicalReportResponseModel.invoiceNoVP : patientMedicalReportResponseModel.invoiceNo,
      "InvoiceNo_VP": Utils.isVidaPlusProject(patientMedicalReportResponseModel.projectID!) ? patientMedicalReportResponseModel.invoiceNoVP : patientMedicalReportResponseModel.invoiceNo,
      "PrintedByName": "${authenticatedUser.firstName!} ${authenticatedUser.lastName!}",
    };

    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        GET_MEDICAL_REPORT_PDF,
        body: mapDevice,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            // final list = response['List_SickLeave'];
            // if (list == null || list.isEmpty) {
            //   throw Exception("lab list is empty");
            // }

            // final vaccinesList = list.map((item) => PatientSickLeavesResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientSickLeavesResponseModel>();

            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: response["MedicalReportBase64"],
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<List<FamilyFileResponseModelLists>>>> getPatientFamilyFiles(int? status, int patientID) async {
    try {
      GenericApiModel<List<FamilyFileResponseModelLists>>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.getAllSharedRecordsByStatus,
        body: {if (status != null) "Status": status, "PatientID": patientID.toString()},
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final list = response['GetAllSharedRecordsByStatusList'] ?? [];

            final familyLists = list.map((item) => FamilyFileResponseModelLists.fromJson(item as Map<String, dynamic>)).toList().cast<FamilyFileResponseModelLists>();

            apiResponse = GenericApiModel<List<FamilyFileResponseModelLists>>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: familyLists,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<List<FamilyFileResponseModelLists>>>> getAllPendingRecordsByResponseId({required Map<String, dynamic> request}) async {
    try {
      GenericApiModel<List<FamilyFileResponseModelLists>>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.getAllPendingRecordsByResponseId,
        body: request,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final list = response['GetAllPendingRecordsList'] ?? [];
            final familyLists = list.map((item) => FamilyFileResponseModelLists.fromJson(item as Map<String, dynamic>)).toList().cast<FamilyFileResponseModelLists>();

            apiResponse = GenericApiModel<List<FamilyFileResponseModelLists>>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: familyLists,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<dynamic>>> addFamilyFile({dynamic request}) async {
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.addFamilyFile,
        body: request,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: response["ShareFamilyFileObj"] ?? null,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<dynamic>>> removeFamilyFile({required int? id}) async {
    Map<String, dynamic> request = {};
    request["ID"] = id;
    request['IsActive'] = false;
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.removeFileFromFamilyMembers,
        body: request,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: response,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<dynamic>>> acceptRejectFamilyFile({required int? id, required int? status}) async {
    Map<String, dynamic> request = {};
    request["ID"] = id;
    request['Status'] = status;
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.acceptAndRejectFamilyFile,
        body: request,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: response,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<List<PatientAppointmentHistoryResponseModel>>>> getPatientAppointmentsForMedicalReport() async {
    Map<String, dynamic> mapDevice = {
      "IsActiveAppointment": false,
      "IsComingFromCOC": false,
      "isForUpcomming": false,
      "IsForMedicalReport": true,
      "IsForArrived": false,
    };

    try {
      GenericApiModel<List<PatientAppointmentHistoryResponseModel>>? apiResponse;
      Failure? failure;
      await apiClient.post(
        GET_PATIENT_APPOINTMENT_HISTORY_ASYNC,
        body: mapDevice,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final list = response['AppoimentAllHistoryResultList'];

            final appointmentsList = list.map((item) => PatientAppointmentHistoryResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientAppointmentHistoryResponseModel>();

            apiResponse = GenericApiModel<List<PatientAppointmentHistoryResponseModel>>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: appointmentsList,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<dynamic>>> insertRequestForMedicalReport({required PatientAppointmentHistoryResponseModel appointmentHistoryResponseModel}) async {
    Map<String, dynamic> mapDevice = {
      "ClinicID": appointmentHistoryResponseModel.clinicID,
      "DoctorID": appointmentHistoryResponseModel.doctorID,
      "SetupID": appointmentHistoryResponseModel.setupID,
      "EncounterNo": appointmentHistoryResponseModel.appointmentNo,
      "EncounterType": 1,
      "IsActive": appointmentHistoryResponseModel.isActiveDoctor,
      "ProjectID": appointmentHistoryResponseModel.projectID,
      "Remarks": "",
      "ProcedureId": "",
      "RequestType": 1,
      "Source": 2,
      "Status": 1,
      "CreatedBy": 102
    };

    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        INSERT_REQUEST_FOR_MEDICAL_REPORT,
        body: mapDevice,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            apiResponse = GenericApiModel<dynamic>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: response,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<List<GetAllergiesResponseModel>>>> getPatientAllergiesList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
    Map<String, dynamic> mapDevice = {"isDentalAllowedBackend": false, "OutSA": 0};

    try {
      GenericApiModel<List<GetAllergiesResponseModel>>? apiResponse;
      Failure? failure;
      await apiClient.post(
        GET_PATIENT_ALLERGIES,
        body: mapDevice,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final list = response['Patient_Allergies'];

            final vaccinesList = list.map((item) => GetAllergiesResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetAllergiesResponseModel>();

            apiResponse = GenericApiModel<List<GetAllergiesResponseModel>>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: null,
              data: vaccinesList,
            );
          } catch (e) {
            failure = DataParsingFailure(e.toString());
          }
        },
      );
      if (failure != null) return Left(failure!);
      if (apiResponse == null) return Left(ServerFailure("Unknown error"));
      return Right(apiResponse!);
    } catch (e) {
      return Left(UnknownFailure(e.toString()));
    }
  }
}
