import 'dart:async';

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/common_models/privilege/PrivilegeModel.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/authentication/models/request_models/check_activation_code_register_request_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';

abstract class AuthenticationRepo {
  Future<Either<Failure, GenericApiModel<dynamic>>> getServicePrivilege();

  Future<Either<Failure, GenericApiModel<SelectDeviceByImeiRespModelElement>>> selectDeviceByImei({required String firebaseToken});

  Future<Either<Failure, GenericApiModel<dynamic>>> checkPatientAuthentication({required dynamic checkPatientAuthenticationReq});

  Future<Either<Failure, GenericApiModel<dynamic>>> sendActivationCodeRepo({required dynamic sendActivationCodeReq, String? languageID, bool isRegister = false});

  Future<Either<Failure, GenericApiModel<dynamic>>> checkActivationCodeRepo(
      {required dynamic newRequest, // could be CheckActivationCodeReq or CheckActivationCodeRegisterReq
      required String? activationCode,
      required bool isRegister});

  Future<Either<Failure, GenericApiModel<dynamic>>> checkIfUserAgreed({required dynamic commonAuthanticatedRequest});

  Future<Either<Failure, GenericApiModel<dynamic>>> getUserAgreementContent({required dynamic commonAuthanticatedRequest});

  Future<Either<Failure, GenericApiModel<dynamic>>> checkPatientForRegistration({required dynamic commonAuthanticatedRequest});

  Future<Either<Failure, GenericApiModel<dynamic>>> checkUserStatus({required dynamic commonAuthanticatedRequest});

  Future<Either<Failure, GenericApiModel<dynamic>>> registerUser({required dynamic registrationPayloadDataModelRequest});

  Future<Either<Failure, GenericApiModel<dynamic>>> insertPatientIMEIData({required dynamic patientIMEIDataRequest});

  Future<Either<Failure, GenericApiModel<dynamic>>> insertPatientDeviceData({required dynamic patientDeviceDataRequest});

  Future<Either<Failure, GenericApiModel<dynamic>>> getPatientDeviceData({required dynamic patientDeviceDataRequest});
}

class AuthenticationRepoImp implements AuthenticationRepo {
  final ApiClient apiClient;
  final LoggerService loggerService;

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

  @override
  Future<Either<Failure, GenericApiModel<SelectDeviceByImeiRespModelElement>>> selectDeviceByImei({required String firebaseToken}) async {
    Map<String, dynamic> mapDevice = {"IMEI": firebaseToken};
    try {
      GenericApiModel<SelectDeviceByImeiRespModelElement>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.selectDeviceImei,
        body: mapDevice,
        onFailure: (error, statusCode, {messageStatus, failureType}) {
          failure = failureType;
        },
        onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
          try {
            final list = response['Patient_SELECTDeviceIMEIbyIMEIList'];
            if (list == null || list.isEmpty) {
              apiResponse = GenericApiModel<SelectDeviceByImeiRespModelElement>(
                messageStatus: messageStatus,
                statusCode: statusCode,
                errorMessage: errorMessage,
                data: null,
              );
              return;
            }

            final model = SelectDeviceByImeiRespModelElement.fromJson(list[0] as Map<String, dynamic>);
            apiResponse = GenericApiModel<SelectDeviceByImeiRespModelElement>(
              messageStatus: messageStatus,
              statusCode: statusCode,
              errorMessage: errorMessage,
              data: model,
            );
          } 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>>> checkPatientAuthentication({
    required dynamic checkPatientAuthenticationReq,
    String? languageID,
  }) async {
    int isOutKsa = (checkPatientAuthenticationReq.zipCode == '966' || checkPatientAuthenticationReq.zipCode == '+966') ? 0 : 1;
    checkPatientAuthenticationReq.patientOutSA = isOutKsa;
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.checkPatientAuth,
        body: checkPatientAuthenticationReq.toJson(),
        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>>> sendActivationCodeRepo({
    required dynamic sendActivationCodeReq,
    String? languageID,
    bool isRegister = false,
  }) async {
    int isOutKsa = (sendActivationCodeReq.zipCode == '966' || sendActivationCodeReq.zipCode == '+966') ? 0 : 1;
    sendActivationCodeReq.patientOutSA = isOutKsa;
    sendActivationCodeReq.isDentalAllowedBackend = false;

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

      await apiClient.post(
        isRegister ? ApiConsts.sendActivationCodeRegister : ApiConsts.sendActivationCode,
        body: sendActivationCodeReq.toJson(),
        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>>> checkActivationCodeRepo({
    required dynamic newRequest, // could be CheckActivationCodeReq or CheckActivationCodeRegisterReq
    required String? activationCode,
    required bool isRegister,
  }) async {
    if (isRegister) {
      newRequest["activationCode"] = activationCode ?? "0000";
      newRequest["isSilentLogin"] = activationCode != null ? false : true;
    } else {
      newRequest.activationCode = activationCode ?? "0000";
      newRequest.isSilentLogin = activationCode != null ? false : true;
      newRequest.projectOutSA = newRequest.zipCode == '966' ? false : true;
      newRequest.isDentalAllowedBackend = false;
      newRequest.forRegisteration = newRequest.isRegister ?? false;
      newRequest.isRegister = false;
    }

    final endpoint = isRegister ? ApiConsts.checkActivationCodeRegister : ApiConsts.checkActivationCode;

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

      await apiClient.post(
        endpoint,
        body: isRegister ? newRequest : newRequest.toJson(),
        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>>> checkIfUserAgreed({required dynamic commonAuthanticatedRequest}) async {
    commonAuthanticatedRequest['Region'] = 1;
    print("dsfsdd");
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.checkUsageAgreement,
        body: commonAuthanticatedRequest,
        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>>> getUserAgreementContent({required dynamic commonAuthanticatedRequest}) async {
    commonAuthanticatedRequest['Region'] = 1;
    print("dsfsdd");
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.getUserAgreementContent,
        body: commonAuthanticatedRequest,
        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>>> checkPatientForRegistration({required dynamic commonAuthanticatedRequest}) async {
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.checkPatientForRegistration,
        body: commonAuthanticatedRequest,
        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>>> checkUserStatus({required dynamic commonAuthanticatedRequest}) async {
    commonAuthanticatedRequest['Region'] = 1;
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.checkUserStatus,
        body: commonAuthanticatedRequest,
        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>>> registerUser({required dynamic registrationPayloadDataModelRequest}) async {
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      await apiClient.post(
        ApiConsts.registerUser,
        body: registrationPayloadDataModelRequest,
        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>> insertPatientIMEIData({required patientIMEIDataRequest}) {
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      return apiClient.post(
        ApiConsts.insertPatientDeviceIMEIData,
        body: patientIMEIDataRequest,
        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());
          }
        },
      ).then((_) {
        if (failure != null) return Left(failure!);
        if (apiResponse == null) return Left(ServerFailure("Unknown error"));
        return Right(apiResponse!);
      });
    } catch (e) {
      return Future.value(Left(UnknownFailure(e.toString())));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel>> insertPatientDeviceData({required patientDeviceDataRequest}) {
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      return apiClient.post(
        ApiConsts.insertPatientMobileData,
        body: patientDeviceDataRequest,
        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());
          }
        },
      ).then((_) {
        if (failure != null) return Left(failure!);
        if (apiResponse == null) return Left(ServerFailure("Unknown error"));
        return Right(apiResponse!);
      });
    } catch (e) {
      return Future.value(Left(UnknownFailure(e.toString())));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel<dynamic>>> getServicePrivilege() {
    Map<String, dynamic> mapDevice = {};
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      return apiClient.post(
        ApiConsts.getPrivileges,
        body: mapDevice,
        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());
          }
        },
      ).then((_) {
        if (failure != null) return Left(failure!);
        if (apiResponse == null) return Left(ServerFailure("Unknown error"));
        return Right(apiResponse!);
      });
    } catch (e) {
      return Future.value(Left(UnknownFailure(e.toString())));
    }
  }

  @override
  Future<Either<Failure, GenericApiModel>> getPatientDeviceData({required patientDeviceDataRequest}) {
    try {
      GenericApiModel<dynamic>? apiResponse;
      Failure? failure;
      return apiClient.post(
        ApiConsts.getPatientMobileData,
        body: patientDeviceDataRequest,
        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());
          }
        },
      ).then((_) {
        if (failure != null) return Left(failure!);
        if (apiResponse == null) return Left(ServerFailure("Unknown error"));
        return Right(apiResponse!);
      });
    } catch (e) {
      return Future.value(Left(UnknownFailure(e.toString())));
    }
  }
}
