import 'dart:io';

import 'package:doctor_app_flutter/config/shared_pref_kay.dart';
import 'package:doctor_app_flutter/core/enum/auth_method_types.dart';
import 'package:doctor_app_flutter/core/enum/view_state.dart';
import 'package:doctor_app_flutter/core/model/auth/activation_Code_req_model.dart';
import 'package:doctor_app_flutter/core/model/auth/activation_code_for_verification_screen_model.dart';
import 'package:doctor_app_flutter/core/model/auth/check_activation_code_for_doctor_app_response_model.dart';
import 'package:doctor_app_flutter/core/model/auth/check_activation_code_request_model.dart';
import 'package:doctor_app_flutter/core/model/auth/imei_details.dart';
import 'package:doctor_app_flutter/core/model/auth/insert_imei_model.dart';
import 'package:doctor_app_flutter/core/model/auth/new_login_information_response_model.dart';
import 'package:doctor_app_flutter/core/model/auth/send_activation_code_for_doctor_app_response_model.dart';
import 'package:doctor_app_flutter/core/model/doctor/clinic_model.dart';
import 'package:doctor_app_flutter/core/model/doctor/doctor_profile_model.dart';
import 'package:doctor_app_flutter/core/model/doctor/profile_req_Model.dart';
import 'package:doctor_app_flutter/core/model/doctor/user_model.dart';
import 'package:doctor_app_flutter/core/model/hospitals/VidaPlusProjectListModel.dart';
import 'package:doctor_app_flutter/core/model/hospitals/get_hospitals_request_model.dart';
import 'package:doctor_app_flutter/core/model/hospitals/get_hospitals_response_model.dart';
import 'package:doctor_app_flutter/core/service/authentication_service.dart';
import 'package:doctor_app_flutter/core/service/hospitals/hospitals_service.dart';
import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart';
import 'package:doctor_app_flutter/locator.dart';
import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart';
import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart';
import 'package:doctor_app_flutter/utils/utils.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/services.dart';
// import 'package:huawei_hmsavailability/huawei_hmsavailability.dart';
// import 'package:local_auth/auth_strings.dart';
import 'package:local_auth/local_auth.dart';
import 'package:local_auth_ios/local_auth_ios.dart';

enum APP_STATUS { LOADING, UNAUTHENTICATED, AUTHENTICATED, UNVERIFIED }

class AuthenticationViewModel extends BaseViewModel {
  AuthenticationService _authService = locator<AuthenticationService>();
  HospitalsService _hospitalsService = locator<HospitalsService>();
    get errorCode => _authService.errorCode;

  List<GetIMEIDetailsModel> get imeiDetails => _authService.dashboardItemsList;

  List<GetHospitalsResponseModel> get hospitals => _hospitalsService.hospitals;

  NewLoginInformationModel get loginInfo => _authService.loginInfo;

  List<DoctorProfileModel> get doctorProfilesList => _authService.doctorProfilesList;

  SendActivationCodeForDoctorAppResponseModel get activationCodeVerificationScreenRes => _authService.activationCodeVerificationScreenRes;

  SendActivationCodeForDoctorAppResponseModel get activationCodeForDoctorAppRes => _authService.activationCodeForDoctorAppRes;

  CheckActivationCodeForDoctorAppResponseModel get checkActivationCodeForDoctorAppRes => _authService.checkActivationCodeForDoctorAppRes;

  List<VidaPlusProjectListModel> get vidaPlusProjectList => _hospitalsService.vidaPlusProjectListModel;

  NewLoginInformationModel? loggedUser;
  GetIMEIDetailsModel? user;

  UserModel userInfo = UserModel();
  final LocalAuthentication auth = LocalAuthentication();
  List<BiometricType>? _availableBiometrics;
  late FirebaseMessaging _firebaseMessaging;

  bool isLogin = false;
  bool unverified = false;
  bool isFromLogin = false;
  APP_STATUS appStatus = APP_STATUS.LOADING;
  String? localToken = "";
  bool isHuawei = false;

  AuthenticationViewModel({bool checkDeviceInfo = false}) {
     FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
    // getDeviceInfoFromFirebase();
    // getDoctorProfile();
  }

  Future<void> initializeApp({String? token}) async {
    setState(ViewState.Busy);
    try {
      localToken = token;
      await getDeviceInfoFromFirebase();
      if (imeiDetails.isNotEmpty) {
        user = imeiDetails.first;
        sharedPref.setObj(LAST_LOGIN_USER, user!);
        unverified = true;
        appStatus = APP_STATUS.UNVERIFIED;
      } else {
        appStatus = APP_STATUS.UNAUTHENTICATED;
      }
      setState(ViewState.Idle);
    } catch (e) {
      error = e.toString();
      appStatus = APP_STATUS.UNAUTHENTICATED;
      setState(ViewState.ErrorLocal);
    }
  }

  /// Insert Device IMEI
  Future insertDeviceImei(token) async {
    var loggedIn = await sharedPref.getObj(LOGGED_IN_USER);
    var data = await sharedPref.getObj(LAST_LOGIN_USER);
    if (data != null) {
      user = GetIMEIDetailsModel.fromJson(data);
    }

    var profileInfo = await sharedPref.getObj(DOCTOR_PROFILE);

    profileInfo['IMEI'] = token;
    profileInfo['LogInTypeID'] = await sharedPref.getInt(OTP_TYPE);
    profileInfo['BioMetricEnabled'] = true;
    profileInfo['MobileNo'] = loggedIn != null ? loggedIn['MobileNumber'] : user!.mobile;
    InsertIMEIDetailsModel insertIMEIDetailsModel = InsertIMEIDetailsModel.fromJson(profileInfo);
    insertIMEIDetailsModel.genderDescription = profileInfo['Gender_Description'];
    insertIMEIDetailsModel.genderDescriptionN = profileInfo['Gender_DescriptionN'];
    insertIMEIDetailsModel.genderDescriptionN = profileInfo['Gender_DescriptionN'];
    insertIMEIDetailsModel.titleDescription = profileInfo['Title_Description'];
    insertIMEIDetailsModel.titleDescriptionN = profileInfo['Title_DescriptionN'];
    insertIMEIDetailsModel.projectID = await sharedPref.getInt(PROJECT_ID);
    insertIMEIDetailsModel.doctorID = loggedIn != null ? loggedIn['List_MemberInformation'][0]['MemberID'] : user!.doctorID;
    insertIMEIDetailsModel.outSA = loggedIn != null ? loggedIn['ZipCode'].toString() =='966' ? false: true   : user!.outSA;
    insertIMEIDetailsModel.vidaAuthTokenID = await sharedPref.getString(VIDA_AUTH_TOKEN_ID);
    insertIMEIDetailsModel.vidaRefreshTokenID = await sharedPref.getString(VIDA_REFRESH_TOKEN_ID);
    insertIMEIDetailsModel.password = userInfo.password;
    insertIMEIDetailsModel.loginDoctorID = loggedUser != null ? loggedUser!.listMemberInformation![0].employeeID : user!.editedBy;
    insertIMEIDetailsModel.zipCode =  loggedIn != null ? loggedIn['ZipCode'] : user!.zipCode;
    await _authService.insertDeviceImei(insertIMEIDetailsModel);
    if (_authService.hasError) {
      error = _authService.error;
      setState(ViewState.ErrorLocal);
    } else
      setState(ViewState.Idle);
  }

  /// first step login
  Future login(UserModel userInfo) async {
    setState(ViewState.BusyLocal);
    await _authService.login(userInfo);
    if (_authService.hasError) {
      error = _authService.error;
      setState(ViewState.ErrorLocal);
    } else {
      sharedPref.setInt(PROJECT_ID, userInfo.projectID!);
      loggedUser = loginInfo;
      saveObjToString(LOGGED_IN_USER, loginInfo);
      sharedPref.remove(LAST_LOGIN_USER);
      sharedPref.setString(TOKEN, loginInfo.logInTokenID!);
      setState(ViewState.Idle);
    }
  }

  /// send activation code for for msg methods
  Future sendActivationCodeVerificationScreen(AuthMethodTypes authMethodType) async {
    setState(ViewState.BusyLocal);
    ActivationCodeForVerificationScreenModel activationCodeModel = ActivationCodeForVerificationScreenModel(
        iMEI: user!.iMEI,
        facilityId: user!.projectID,
        memberID: user!.doctorID,
        loginDoctorID: int.parse(user!.editedBy.toString()),
        zipCode: user!.outSA == true ? '971' : '966',
        mobileNumber: user!.mobile,
        oTPSendType: authMethodType.getTypeIdService(),
        isMobileFingerPrint: 1,
        vidaAuthTokenID: user!.vidaAuthTokenID,
        vidaRefreshTokenID: user!.vidaRefreshTokenID);
    await sharedPref.setString(DOCTOR_ID, user!.editedBy.toString());

    await _authService.sendActivationCodeVerificationScreen(activationCodeModel);
    if (_authService.hasError) {
      error = _authService.error;
      setState(ViewState.ErrorLocal);
    } else
      setState(ViewState.Idle);
  }

  /// send activation code for silent login
  Future sendActivationCodeForDoctorApp({required AuthMethodTypes authMethodType, required String password}) async {
    setState(ViewState.BusyLocal);
    int projectID = await sharedPref.getInt(PROJECT_ID);
    ActivationCodeModel activationCodeModel = ActivationCodeModel(
      facilityId: projectID,
      memberID: loggedUser!.listMemberInformation![0].memberID,
      loginDoctorID: loggedUser!.listMemberInformation![0].employeeID,
      otpSendType: authMethodType.getTypeIdService().toString(),
    );
    await sharedPref.setString(DOCTOR_ID, (loggedUser!.listMemberInformation![0].employeeID).toString());
    await _authService.sendActivationCodeForDoctorApp(activationCodeModel);
    if (_authService.hasError) {
      error = _authService.error;
      setState(ViewState.ErrorLocal);
    } else {
      await sharedPref.setString(TOKEN, _authService.activationCodeForDoctorAppRes.logInTokenID!);
      setState(ViewState.Idle);
    }
  }

  /// check activation code for sms and whats app
  Future checkActivationCodeForDoctorApp({String? activationCode, bool isSilentLogin = false}) async {
    setState(ViewState.BusyLocal);

    CheckActivationCodeRequestModel checkActivationCodeForDoctorApp = new CheckActivationCodeRequestModel(
        zipCode: loggedUser != null ? loggedUser!.zipCode : user!.zipCode,
        mobileNumber: loggedUser != null ? loggedUser!.mobileNumber : user!.mobile,
        projectID: await sharedPref.getInt(PROJECT_ID) != null ? await sharedPref.getInt(PROJECT_ID) : user!.projectID,
        logInTokenID: await sharedPref.getString(TOKEN),
        activationCode: activationCode ?? '0000',
        memberID: userInfo.userID != null ? int.parse(userInfo.userID!) : user!.doctorID,
        password: userInfo.password,
        facilityId: userInfo.projectID != null ? userInfo.projectID.toString() : user!.projectID.toString(),
        oTPSendType: await sharedPref.getInt(OTP_TYPE),
        iMEI: localToken,
        loginDoctorID: loggedUser != null ? loggedUser!.listMemberInformation![0].employeeID : int.parse(user!.editedBy.toString()),

        ///loggedUser.listMemberInformation[0].employeeID,
        // loggedUser.listMemberInformation[0].employeeID,
        isForSilentLogin: isSilentLogin,
        generalid: "Cs2020@2016\$2958");
    await _authService.checkActivationCodeForDoctorApp(checkActivationCodeForDoctorApp);
    if (_authService.hasError) {
      error = _authService.error;
      setState(ViewState.ErrorLocal);
    } else {

      await setDataAfterSendActivationSuccess(checkActivationCodeForDoctorAppRes);
      setState(ViewState.Idle);
    }
  }

  /// get list of Hospitals
  Future getHospitalsList(memberID) async {
    GetHospitalsRequestModel getHospitalsRequestModel = GetHospitalsRequestModel();
    getHospitalsRequestModel.memberID = memberID;
    getHospitalsRequestModel.doctorID = memberID;

    await _hospitalsService.getHospitals(getHospitalsRequestModel);
    if (_hospitalsService.hasError) {
      error = _hospitalsService.error;
      setState(ViewState.Error);
    } else
      setState(ViewState.Idle);
  }

  /// get type name based on id.
  getType(type, context) {
    switch (type) {
      case 1:
        return TranslationBase.of(context).verifySMS;
        break;
      case 3:
        return TranslationBase.of(context).verifyFingerprint;
        break;
      case 4:
        return TranslationBase.of(context).verifyFaceID;
        break;
      case 2:
        return TranslationBase.of(context).verifyWhatsApp;
        break;
      default:
        return TranslationBase.of(context).verifySMS;
        break;
    }
  }

  /// add token to shared preferences in case of send activation code is success
  setDataAfterSendActivationSuccess(CheckActivationCodeForDoctorAppResponseModel sendActivationCodeForDoctorAppResponseModel) async {
    // print("VerificationCode : " + sendActivationCodeForDoctorAppResponseModel.verificationCode);
    await sharedPref.setString(
        DOCTOR_SETUP_ID, sendActivationCodeForDoctorAppResponseModel.listDoctorsClinic![0].setupID != null ? sendActivationCodeForDoctorAppResponseModel.listDoctorsClinic![0].setupID! : "");
    await sharedPref.setString(VIDA_AUTH_TOKEN_ID, sendActivationCodeForDoctorAppResponseModel.vidaAuthTokenID!);
    await sharedPref.setString(VIDA_REFRESH_TOKEN_ID, sendActivationCodeForDoctorAppResponseModel.vidaRefreshTokenID!);
    await sharedPref.setString(TOKEN, sendActivationCodeForDoctorAppResponseModel.authenticationTokenID!);
  }

  saveObjToString(String key, value) async {
    sharedPref.setObj(key, value);
  }

  /// ask user to add his biometric
  showIOSAuthMessages() async {
    const iosStrings = IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please Enable Your Touch ID');
    try {
      await auth.authenticate(
        localizedReason: 'Scan your fingerprint to authenticate',
        authMessages: [iosStrings],
        options: AuthenticationOptions(
          useErrorDialogs: true,
          stickyAuth: true,
        ),
      );
    } on PlatformException catch (e) {
      DrAppToastMsg.showErrorToast(e.toString());
    }
  }

  /// add profile to base view model super class
  localSetDoctorProfile(DoctorProfileModel profile) {
    super.setDoctorProfile(profile);
  }

  /// get doctor profile based on clinic model
  Future getDoctorProfileBasedOnClinic(ClinicModel clinicInfo) async {
    ProfileReqModel docInfo = new ProfileReqModel(doctorID: clinicInfo.doctorID, clinicID: clinicInfo.clinicID, license: true, projectID: clinicInfo.projectID, languageID: 2);

    ///TODO change the lan
    await _authService.getDoctorProfileBasedOnClinic(docInfo);
    if (_authService.hasError) {
      error = _authService.error;
      setState(ViewState.ErrorLocal);
    } else {
      localSetDoctorProfile(doctorProfilesList.first);
      setState(ViewState.Idle);
    }
  }

  /// add some logic in case of check activation code is success
  onCheckActivationCodeSuccess({bool isSilentLogin = false}) async {
    sharedPref.setString(TOKEN, checkActivationCodeForDoctorAppRes.authenticationTokenID!);
    if (checkActivationCodeForDoctorAppRes.listDoctorProfile != null && checkActivationCodeForDoctorAppRes.listDoctorProfile!.isNotEmpty) {
      localSetDoctorProfile(checkActivationCodeForDoctorAppRes.listDoctorProfile![0]);
    } else {
      sharedPref.setObj(CLINIC_NAME, checkActivationCodeForDoctorAppRes.listDoctorsClinic);
      ClinicModel clinic = ClinicModel.fromJson(checkActivationCodeForDoctorAppRes.listDoctorsClinic![0].toJson());
      await getDoctorProfileBasedOnClinic(clinic);
    }
  }

  /// check specific biometric if it available or not
  Future<bool> checkIfBiometricAvailable(BiometricType biometricType) async {
    bool isAvailable = false;
    await _getAvailableBiometrics();
    if (_availableBiometrics != null) {
      for (var i = 0; i < _availableBiometrics!.length; i++) {
        if (biometricType == _availableBiometrics![i]) isAvailable = true;
      }
    }
    return isAvailable;
  }

  /// get all available biometric on the device for local Auth service
  Future<void> _getAvailableBiometrics() async {
    try {
      _availableBiometrics = await auth.getAvailableBiometrics();
    } on PlatformException catch (e) {
      print(e);
    }
  }

  // checkIsHuawei() async {
  //   HmsApiAvailability hmsApiAvailability = HmsApiAvailability();
  //   await hmsApiAvailability.isHMSAvailable().then((value) {
  //     isHuawei = value == 0 ? true : false;
  //   });
  //   print(isHuawei);
  // }

  /// call firebase service to check if the user already login in before or not
  // getDeviceInfoFromFirebase() async {
  //   // await checkIsHuawei();
  //   var token;
  //   var APNSToken;
  //   _firebaseMessaging.setAutoInitEnabled(true);
  //   if (Platform.isIOS) {
  //     _firebaseMessaging.requestPermission();
  //   }
  //   setState(ViewState.Busy);
  //   try {
  //     if (Platform.isIOS) {
  //       APNSToken = await _firebaseMessaging.getAPNSToken();
  //       print("APNS TOKEN: $APNSToken");
  //     }
  //     token = await _firebaseMessaging.getToken();
  //     print("Device TOKEN: $token");
  //   } catch (ex) {
  //     print(ex);
  //   }
  //   if (localToken == "") {
  //     localToken = token;
  //     await _authService.selectDeviceImei(localToken);
  //     if (_authService.hasError) {
  //       error = _authService.error;
  //       setState(ViewState.ErrorLocal);
  //     } else {
  //       if (_authService.dashboardItemsList.length > 0) {
  //         user = _authService.dashboardItemsList[0];
  //         sharedPref.setObj(LAST_LOGIN_USER, _authService.dashboardItemsList[0]);
  //         // await sharedPref.setString(VIDA_REFRESH_TOKEN_ID, user!.vidaRefreshTokenID!);
  //         // await sharedPref.setString(VIDA_AUTH_TOKEN_ID, user!.vidaAuthTokenID!);
  //         this.unverified = true;
  //       }
  //       setState(ViewState.Idle);
  //     }
  //   } else {
  //     setState(ViewState.Idle);
  //   }
  // }
  Future<void> getDeviceInfoFromFirebase() async {
    try {
      // Only call API if we have a token
      if (localToken != null && localToken!.isNotEmpty) {
        await _authService.selectDeviceImei(localToken!);

        if (_authService.hasError) {
          throw Exception(_authService.error);
        }
      }
    } catch (e) {
      // debugPrint("Error getting device info: $e");
      rethrow;
    }
  }
  /// determine the status of the app
  APP_STATUS get status {
    if (state == ViewState.Busy) {
      appStatus = APP_STATUS.LOADING;
    } else {
      if (this.doctorProfile != null)
        appStatus = APP_STATUS.AUTHENTICATED;
      else if (this.unverified) {
        appStatus = APP_STATUS.UNVERIFIED;
      } else if (this.isLogin) {
        appStatus = APP_STATUS.AUTHENTICATED;
      } else {
        appStatus = APP_STATUS.UNAUTHENTICATED;
      }
    }
    return appStatus;
  }

  setAppStatus(APP_STATUS status) {
    this.appStatus = status;
    notifyListeners();
  }

  setUnverified(bool unverified, {bool isFromLogin = false}) {
    this.unverified = unverified;
    this.isFromLogin = isFromLogin;
    notifyListeners();
  }

  /// logout function
  logout({bool isFromLogin = false}) async {
    localToken = "";
    String? lang = await sharedPref.getString(APP_Language);

    //COMMENTED THE NOT TO CLEAR THE SHARED PREF
    // await Utils.clearSharedPref();
    doctorProfile = null;
    sharedPref.setString(APP_Language, lang ?? 'en');
    deleteUser();
    await getDeviceInfoFromFirebase();
    this.isFromLogin = isFromLogin;
    appStatus = APP_STATUS.UNAUTHENTICATED;
    setState(ViewState.Idle);
  }

  deleteUser() async{
    await Utils.clearSharedPref();
    user = null;
    doctorProfile = null;
    appStatus = APP_STATUS.UNAUTHENTICATED;
    unverified = false;
    isLogin = false;
  }
}
