import 'dart:convert';
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/loading_utils.dart';
import 'package:hmg_patient_app_new/core/utils/request_utils.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_activation_code_resp_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart';
import 'package:hmg_patient_app_new/presentation/authentication/login.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';

class AuthenticationViewModel extends ChangeNotifier {
  final AuthenticationRepo _authenticationRepo;
  final AppState _appState;
  final ErrorHandlerService _errorHandlerService;
  final DialogService _dialogService;
  final NavigationService _navigationService;

  AuthenticationViewModel({
    required AppState appState,
    required AuthenticationRepo authenticationRepo,
    required ErrorHandlerService errorHandlerService,
    required DialogService dialogService,
    required NavigationService navigationService,
    required CacheService cacheService,
  })  : _navigationService = navigationService,
        _dialogService = dialogService,
        _errorHandlerService = errorHandlerService,
        _appState = appState,
        _authenticationRepo = authenticationRepo;

  final TextEditingController nationalIdController = TextEditingController(), phoneNumberController = TextEditingController(), dobController = TextEditingController();
  CountryEnum selectedCountrySignup = CountryEnum.saudiArabia;
  MaritalStatusTypeEnum? maritalStatus;
  GenderTypeEnum? genderType;
  bool isTermsAccepted = false;
  List<NationalityCountries>? countriesList;

  NationalityCountries? pickedCountryByUAEUser;

  bool isDubai = false;
  bool authenticated = false;
  late int mobileNumber;
  String errorMsg = '';
  var registerd_data;
  bool isMoreOption = false;
  var zipCode;
  var patientOutSA;
  var loginTokenID;
  var loginType;
  var deviceToken;
  var lastLogin;
  final FocusNode myFocusNode = FocusNode();
  late int selectedOption = 1;
  bool onlySMSBox = false;
  int fingrePrintBefore = 0;
  var dob;
  late int isHijri;
  var healthId;

  Future<void> onLoginPressed() async {
    try {
      LoadingUtils.showFullScreenLoader();
      //TODO:  We will remove this delay
      await Future.delayed(Duration(seconds: 3));
      var data = _appState.getSelectDeviceByImeiRespModelElement;
      log("Cached IMEI data: ${data?.toJson()}");
      if (data != null) {
        await _handleExistingImeiData(data);
      } else {
        await _handleNewImeiRegistration();
      }
    } catch (e) {
      log("Error in onLoginPressed: $e");
      LoadingUtils.hideFullScreenLoader();
      _dialogService.showErrorBottomSheet(message: "An unexpected error occurred. Please try again.", onOkPressed: () {});
    }
  }

  void clearDefaults() {
    nationalIdController.clear();
    phoneNumberController.clear();
    dobController.clear();
    maritalStatus = null;
    genderType = null;
    isTermsAccepted = false;
    selectedCountrySignup = CountryEnum.saudiArabia;
    pickedCountryByUAEUser = null;
  }

  void onCountryChange(CountryEnum country) {
    selectedCountrySignup = country;
    notifyListeners();
  }

  void loadCountriesData({required BuildContext context}) async {
    final String response = await DefaultAssetBundle.of(context).loadString('assets/json/countriesList.json');
    final List<dynamic> data = json.decode(response);
    countriesList = data.map((e) => NationalityCountries.fromJson(e)).toList();
  }

  void onMaritalStatusChange(String? status) {
    maritalStatus = MaritalStatusTypeExtension.fromType(status)!;
    notifyListeners();
  }

  void onGenderChange(String? status) {
    genderType = GenderTypeExtension.fromType(status)!;
    notifyListeners();
  }

  void onUAEUserCountrySelection(String? value) {
    pickedCountryByUAEUser = countriesList!.firstWhere((element) => element.name == value);
    notifyListeners();
  }

  void onPhoneNumberChange(String? phoneNumber) {
    phoneNumberController.text = phoneNumber!;
  }

  void onTermAccepted() {
    isTermsAccepted = !isTermsAccepted;
    notifyListeners();
  }

  Future<void> selectDeviceImei({required Function(dynamic data) onSuccess, Function(String)? onError}) async {
    // LoadingUtils.showFullScreenLoading();
    String firebaseToken = _appState.deviceToken == ""
        ? "dOGRRszQQMGe_9wA5Hx3kO:APA91bFV5IcIJXvcCXXk0tc2ddtZgWwCPq7sGSuPr-YW7iiJpQZKgFGN9GAzCVOWL8MfheaP1slE8MdxB7lczdPBGdONQ7WbMmhgHcsUCUktq-hsapGXXqc"
        : _appState.deviceToken;
    final result = await _authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken);

    result.fold(
      (failure) async {
        // LoadingUtils.hideFullScreenLoader();
        await _errorHandlerService.handleError(failure: failure);
      },
      (apiResponse) {
        // LoadingUtils.hideFullScreenLoader();
        log("apiResponse: ${apiResponse.data.toString()}");
        log("messageStatus: ${apiResponse.messageStatus.toString()}");
        if (apiResponse.messageStatus == 1) {
          onSuccess(apiResponse.data);
        } else if (apiResponse.messageStatus == 2) {
          _dialogService.showErrorBottomSheet(message: "Message Status = 2", onOkPressed: () {});
        }
      },
    );
  }

  Future<void> _handleExistingImeiData(dynamic data) async {
    try {
      SelectDeviceByImeiRespModelElement? savedData = _appState.getSelectDeviceByImeiRespModelElement;
      LoadingUtils.hideFullScreenLoader();

      if (savedData != null) {
        // TODO: Navigate to SavedLogin when available
        _navigationService.pushPage(page: LoginScreen());
        // navigationService.pushPage(page: SavedLogin(savedData));
      }
    } catch (e) {
      log("Error handling existing IMEI data: $e");
      LoadingUtils.hideFullScreenLoader();
      _navigationService.pushPage(page: LoginScreen());
    }
  }

  Future<void> _handleNewImeiRegistration() async {
    await selectDeviceImei(onSuccess: (dynamic respData) async {
      try {
        if (respData != null) {
          dynamic data = SelectDeviceByImeiRespModelElement.fromJson(respData.toJson());
          _appState.setSelectDeviceByImeiRespModelElement(data);
          LoadingUtils.hideFullScreenLoader();

          // TODO: Navigate to SavedLogin when available
          // SelectDeviceByImeiRespModelElement savedData =
          //     SelectDeviceByImeiRespModelElement.fromJson(respData);
          // navigationService.pushPage(page: SavedLogin(savedData));
          _navigationService.pushPage(page: LoginScreen());
        } else {
          LoadingUtils.hideFullScreenLoader();
          _navigationService.pushPage(page: LoginScreen());
        }
      } catch (e) {
        log("Error processing IMEI registration response: $e");
        LoadingUtils.hideFullScreenLoader();
        _navigationService.pushPage(page: LoginScreen());
      }
    }, onError: (String error) {
      LoadingUtils.hideFullScreenLoader();
      _dialogService.showErrorBottomSheet(message: error, onOkPressed: () {});
    });
  }

  Future<void> checkUserAuthentication({required OTPTypeEnum otpTypeEnum, Function(dynamic)? onSuccess, Function(String)? onError}) async {
    // TODO: THIS SHOULD BE REMOVED LATER ON AND PASSED FROM APP STATE DIRECTLY INTO API CLIENT. BECAUSE THIS API ONLY NEEDS FEW PARAMS FROM USER

    if (phoneNumberController.text.isEmpty) {
      phoneNumberController.text = "504278212";
    }
    bool isValidated = ValidationUtils.isValidatePhoneAndId(
      phoneNumber: phoneNumberController.text,
      nationalId: nationalIdController.text,
    );

    if (!isValidated) {
      return;
    }

    LoadingUtils.showFullScreenLoader();

    dynamic checkPatientAuthenticationReq = RequestUtils.getPatientAuthenticationRequest(
      phoneNumber: phoneNumberController.text,
      nationId: nationalIdController.text,
      isForRegister: false,
      patientOutSA: false,
      otpTypeEnum: otpTypeEnum,
      patientId: 0,
      zipCode: '966',
    );

    final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq);
    LoadingUtils.hideFullScreenLoader();
    result.fold(
      (failure) async => await _errorHandlerService.handleError(failure: failure),
      (apiResponse) async {
        if (apiResponse.messageStatus == 2) {
          await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty", onOkPressed: () {});
        } else if (apiResponse.messageStatus == 1) {
          if (apiResponse.data['isSMSSent']) {
            _appState.setAppLoginTokenID = apiResponse.data['LogInTokenID'];
            sendActivationCode(
              otpTypeEnum: otpTypeEnum,
              phoneNumber: phoneNumberController.text,
              nationalIdOrFileNumber: nationalIdController.text,
            );
          } else {
            if (apiResponse.data['IsAuthenticated']) {
              await checkActivationCode(
                onWrongActivationCode: (String? message) {},
                activationCode: 0000,
              );
            }
          }
        }
      },
    );
  }

  Future<void> sendActivationCode({
    required OTPTypeEnum otpTypeEnum,
    required String nationalIdOrFileNumber,
    required String phoneNumber,
  }) async {
    var request = RequestUtils.getCommonRequestSendActivationCode(
      otpTypeEnum: otpTypeEnum,
      mobileNumber: phoneNumber,
      selectedLoginType: otpTypeEnum.toInt(),
      zipCode: "966",
      nationalId: nationalIdOrFileNumber,
      isFileNo: false,
      patientId: 0,
      isForRegister: false,
      patientOutSA: false,
    );

    // TODO: GET APP SMS SIGNATURE HERE
    request.sMSSignature = "enKTDcqbOVd";
    // GifLoaderDialogUtils.showMyDialog(context);

    bool isForRegister = healthId != null || isDubai;
    if (isForRegister) {
      if (!isDubai) {
        request.dob = dob; //isHijri == 1 ? dob : dateFormat2.format(dateFormat.parse(dob));
      }
      request.healthId = healthId;
      request.isHijri = isHijri;
    } else {
      // request.dob = "";
      // request.healthId = "";
      // request.isHijri = 0;
    }

    final resultEither = await _authenticationRepo.sendActivationCodeRepo(
      sendActivationCodeReq: request,
      isRegister: isForRegister,
      languageID: 'er',
    );

    resultEither.fold(
      (failure) async => await _errorHandlerService.handleError(failure: failure),
      (apiResponse) async {
        if (apiResponse.messageStatus == 2) {
          await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty");
        } else {
          if (apiResponse.data != null && apiResponse.data['isSMSSent'] == true) {
            navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber);
          } else {
            // TODO: Handle isSMSSent false
            // navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber);
          }
        }
      },
    );
  }

  Future<void> checkActivationCode({
    required int activationCode,
    required Function(String? message) onWrongActivationCode,
  }) async {
    final request = RequestUtils.getCommonRequestWelcome(
      phoneNumber: '0567184134',
      otpTypeEnum: OTPTypeEnum.sms,
      deviceToken: 'dummyDeviceToken123',
      patientOutSA: true,
      loginTokenID: 'dummyLoginToken456',
      registeredData: null,
      patientId: 12345,
      nationIdText: '1234567890',
      countryCode: 'SA',
    ).toJson();

    bool isForRegister = healthId != null || isDubai;
    if (isForRegister) {
      if (isDubai) request['DOB'] = dob;
      request['HealthId'] = healthId;
      request['IsHijri'] = isHijri;

      final resultEither = await _authenticationRepo.checkActivationCodeRepo(
        newRequest: request,
        activationCode: activationCode.toString(),
        isRegister: true,
      );

      resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) {
        final activation = CheckActivationCode.fromJson(apiResponse.data as Map<String, dynamic>);
        if (registerd_data?.isRegister == true) {
          _navigationService.popUntilNamed(AppRoutes.registerNewScreen);
          // Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew));
          return;
        }
      });
    } else {
      final resultEither = await _authenticationRepo.checkActivationCodeRepo(
        newRequest: request,
        activationCode: activationCode.toString(),
        isRegister: false,
      );

      resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) {
        final activation = CheckActivationCode.fromJson(resultEither as Map<String, dynamic>);
        if (activation.errorCode == '699') {
          // Todo: Hide Loader
          // GifLoaderDialogUtils.hideDialog(context);
          onWrongActivationCode(activation.errorEndUserMessage);
          return;
        } else if (registerd_data?.isRegister == true) {
          _navigationService.popUntilNamed(AppRoutes.registerNewScreen);
          // Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew));
          return;
        } else {
          // TODO: setPreferences and stuff
          // sharedPref.remove(FAMILY_FILE);
          // activation.list!.isFamily = false;
          // userData = activation.list;
          // sharedPref.setString(BLOOD_TYPE, activation.patientBloodType ?? "");
          // authenticatedUserObject.user = activation.list!;
          // projectViewModel.setPrivilege(privilegeList: res);
          // await sharedPref.setObject(MAIN_USER, activation.list);
          // await sharedPref.setObject(USER_PROFILE, activation.list);
          // loginTokenID = activation.logInTokenID;
          // await sharedPref.setObject(LOGIN_TOKEN_ID, activation.logInTokenID);
          // await sharedPref.setString(TOKEN, activation.authenticationTokenID!);
          // checkIfUserAgreedBefore(activation);
          // projectViewModel.analytics.loginRegistration.login_successful();
        }
      });
    }
  }

  Future<void> navigateToOTPScreen({required OTPTypeEnum otpTypeEnum, required String phoneNumber}) async {
    _navigationService.pushToOtpScreen(
      phoneNumber: phoneNumber,
      checkActivationCode: (int activationCode) async {
        await checkActivationCode(
            activationCode: activationCode,
            onWrongActivationCode: (String? value) {
              onWrongActivationCode(message: value);
            });
      },
      onResendOTPPressed: (String phoneNumber) {},
    );
  }

  Future<void> onWrongActivationCode({String? message}) async {
    // TODO: HANDLE THIS VIA BOTTOM SHEET
  }

  @override
  void dispose() {
    nationalIdController.dispose();
    phoneNumberController.dispose();
    myFocusNode.dispose();
    super.dispose();
  }
}
