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/exceptions/api_failure.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<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,
  });
}

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 {
    final 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) {
              throw Exception("Device list is empty");
            }

            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 {
    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: 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()));
    }
  }
}
