import 'dart:async';
import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:http/http.dart';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/user_models/basic_otp.dart';
import 'package:mc_common_app/models/user_models/change_email.dart';
import 'package:mc_common_app/models/user_models/change_mobile.dart';
import 'package:mc_common_app/models/user_models/cities.dart';
import 'package:mc_common_app/models/user_models/confirm_email.dart';
import 'package:mc_common_app/models/user_models/confirm_mobile.dart';
import 'package:mc_common_app/models/user_models/confirm_password.dart';
import 'package:mc_common_app/models/user_models/country.dart';
import 'package:mc_common_app/models/user_models/forget_password_otp_compare.dart';
import 'package:mc_common_app/models/user_models/image_response.dart';
import 'package:mc_common_app/models/user_models/login_password.dart';
import 'package:mc_common_app/models/user_models/refresh_token.dart';
import 'package:mc_common_app/models/user_models/register_user.dart';
import 'package:mc_common_app/models/user_models/role.dart';
import 'package:mc_common_app/models/user_models/user.dart';
import 'package:mc_common_app/models/user_models/verify_email.dart';
import 'package:mc_common_app/utils/shared_prefrence.dart';

abstract class UserRepo {
  Future<BasicOtpRespModel> basicOtp(String phoneNo, {int otpType = 1, int roleId = 4, int countryId = 1, bool isNeedToPassToken = false});

  Future<RegisterUserRespModel> basicVerify(String phoneNo, String otp, String userToken, {bool isNeedToPassToken = false});

  Future<RegisterUserRespModel> basicComplete(String userId, String firstName, String lastName, String email, String password, String cityID, String genderID, {bool isNeedToPassToken = false});

  Future<Response> loginV1(String phoneNo, String password);

  Future<LoginPasswordRespModel> loginV2OTP(String userToken, String loginType);

  Future<Response> loginV2OTPVerify(String userToken, String otp, String deviceType, String deviceToken);

  Future<RefreshToken> refreshTokenAPI(String token, String refreshToken);

  Future<Country> getAllCountries();

  Future<Cities> getAllCites(String countryId);

  Future<Role> getRoles();

  Future<Response> forgetPasswordOTPRequest(String userName, int otpType);

  Future<PasswordOTPCompareResModel> forgetPasswordOTPCompare(String userToken, String userOTP);

  Future<ConfirmPasswordRespModel> forgetPassword(String userToken, String newPassword);

  Future<GenericRespModel> changePassword(String currentPassword, String newPassword);

  Future<Map<String, dynamic>> updateUserInfo(String firstName, String lastName, String? city);

  Future<ChangeMobileRespModel> changeMobileNoOTPRequest(countryID, String mobileNo, String password);

  Future<ConfirmMobileRespModel> changeMobileNo(String userToken, String userOTP);

  Future<ChanEmailRespModel> changeEmailOTPRequest(String email, String password);

  Future<ConfirmEmailRespModel> changeEmail(String userToken, String userOTP);

  Future<VerifyEmailRespModel> emailVerify(String email, String userID);

  Future<GenericRespModel> emailVerifyOTPVerify(String userToken, String userOTP);

  Future<ImageResponse> updateUserImage(String image);

  Future<ImageResponse> getUserImage(String image);

  Future<Response> logoutUser();

  Future<String> updateUserToken();
}

class UserRepoImp implements UserRepo {
  @override
  Future<BasicOtpRespModel> basicOtp(String phoneNo, {int otpType = 1, int roleId = 4, int countryId = 1, bool isNeedToPassToken = false}) async {
    var postParams = {"countryID": countryId, "userMobileNo": phoneNo, "otpType": otpType, "userRole": roleId};
    String? t;
    if (isNeedToPassToken) {
      t = AppState().getUser.data!.accessToken ?? "";
      debugPrint("token $t");
    }
    return await injector.get<ApiClient>().postJsonForObject((json) => BasicOtpRespModel.fromJson(json), ApiConsts.basicOTP, postParams, token: t);
  }

  @override
  Future<RegisterUserRespModel> basicVerify(String phoneNo, String otp, String userToken, {bool isNeedToPassToken = false}) async {
    var postParams = {
      "userMobileNo": phoneNo,
      "userOTP": otp,
      "userToken": userToken,
    };
    String? t;
    if (isNeedToPassToken) {
      t = AppState().getUser.data!.accessToken ?? "";
      debugPrint("token $t");
    }
    return await injector.get<ApiClient>().postJsonForObject((json) => RegisterUserRespModel.fromJson(json), ApiConsts.basicVerify, postParams, token: t);
  }

  @override
  Future<RegisterUserRespModel> basicComplete(String userId, String firstName, String lastName, String email, String password, String cityID, String genderID, {bool isNeedToPassToken = false}) async {
    Map<String, Object> postParams;
    if (email.isEmpty) {
      postParams = {"userID": userId, "firstName": firstName, "lastName": lastName, "companyName": "string", "isEmailVerified": true, "password": password, "cityID": cityID, "genderID": genderID};
    } else {
      postParams = {"userID": userId, "firstName": firstName, "lastName": lastName, "email": email, "companyName": "string", "isEmailVerified": true, "password": password, "cityID": cityID, "genderID": genderID};
    }
    String? t;
    if (isNeedToPassToken) {
      t = AppState().getUser.data!.accessToken ?? "";
      debugPrint("token $t");
    }
    return await injector.get<ApiClient>().postJsonForObject((json) => RegisterUserRespModel.fromJson(json), ApiConsts.basicComplete, postParams, token: t);
  }

  @override
  Future<Response> loginV1(String phoneNo, String password) async {
    var postParams = {
      "mobileorEmail": phoneNo,
      "password": password,
    };
    return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.loginV1, postParams);
    //return await injector.get<ApiClient>().postJsonForObject((json) => BasicOtp.fromJson(json), ApiConsts.Login_V1, postParams);
  }

  @override
  Future<LoginPasswordRespModel> loginV2OTP(String userToken, String loginType) async {
    var postParams = {
      "userToken": userToken,
      "loginType": loginType,
    };

    Response response = await injector.get<ApiClient>().postJsonForResponse(ApiConsts.loginV2OTP, postParams);
    LoginPasswordRespModel user = LoginPasswordRespModel.fromJson(jsonDecode(response.body));
    return user;
  }

  @override
  Future<Response> loginV2OTPVerify(
    String userToken,
    String otp,
    String deviceType,
    String deviceToken,
  ) async {
    var postParams = {"userToken": userToken, "userOTP": otp, "deviceType": deviceType, "deviceToken": deviceToken};
    return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.loginV2OTPVerify, postParams);
  }

  @override
  Future<RefreshToken> refreshTokenAPI(String token, String refreshToken) async {
    var postParams = {"token": token, "refreshToken": refreshToken};
    // String t = AppState().getUser.data!.accessToken ?? "";
    return await injector.get<ApiClient>().postJsonForObject((json) => RefreshToken.fromJson(json), ApiConsts.refreshToken, postParams);
  }

  @override
  Future<Country> getAllCountries() async {
    return await injector.get<ApiClient>().getJsonForObject((json) => Country.fromJson(json), ApiConsts.getAllCountry);
  }

  // @override
  // Future<Country> getAllCountriesForUser() async {
  //   return await injector.get<ApiClient>().getJsonForObject((json) => Country.fromJson(json), ApiConsts.getAllCountry);
  // }

  @override
  Future<Cities> getAllCites(String countryId) async {
    var postParams = {
      "CountryID": countryId,
    };
    return await injector.get<ApiClient>().getJsonForObject((json) => Cities.fromJson(json), ApiConsts.getAllCities, queryParameters: postParams);
  }

  @override
  Future<Role> getRoles() async {
    return await injector.get<ApiClient>().getJsonForObject((json) => Role.fromJson(json), ApiConsts.getProviderRoles);
  }

  @override
  Future<Response> forgetPasswordOTPRequest(String userName, int otpType) async {
    var postParams = {
      "userName": userName,
      "otpType": 1,
    };
    return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.forgetPasswordOTPRequest, postParams);
    //return await injector.get<ApiClient>().postJsonForObject((json) => PasswordOTPRequest.fromJson(json), ApiConsts.ForgetPasswordOTPRequest, postParams);
  }

  @override
  Future<PasswordOTPCompareResModel> forgetPasswordOTPCompare(String userToken, String userOTP) async {
    var postParams = {"userToken": userToken, "userOTP": userOTP};
    Response response = await injector.get<ApiClient>().postJsonForResponse(ApiConsts.forgetPasswordOTPCompare, postParams);

    PasswordOTPCompareResModel otpCompare = PasswordOTPCompareResModel.fromJson(jsonDecode(response.body));
    return otpCompare;
  }

  @override
  Future<ConfirmPasswordRespModel> forgetPassword(String userToken, String newPassword) async {
    var postParams = {
      "userToken": userToken,
      "newPassword": newPassword,
    };

    Response response = await injector.get<ApiClient>().postJsonForResponse(ApiConsts.forgetPassword, postParams);
    ConfirmPasswordRespModel data = ConfirmPasswordRespModel.fromJson(jsonDecode(response.body));

    return data;
    //return await injector.get<ApiClient>().postJsonForObject((json) => ConfirmPassword.fromJson(json), ApiConsts.ForgetPassword, postParams);
  }

  @override
  Future<GenericRespModel> changePassword(String currentPassword, String newPassword) async {
    var postParams = {
      "currentPassword": currentPassword,
      "newPassword": newPassword,
    };
    // return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.ChangePassword, postParams);

    String t = AppState().getUser.data!.accessToken ?? "";
    debugPrint("token $t");
    return await injector.get<ApiClient>().postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.changePassword, postParams, token: t);
  }

  @override
  Future<ChangeMobileRespModel> changeMobileNoOTPRequest(countryID, String mobileNo, String password) async {
    var postParams = {"countryID": 1, "mobileNo": mobileNo, "password": password};
    String t = AppState().getUser.data!.accessToken ?? "";
    return await injector.get<ApiClient>().postJsonForObject((json) => ChangeMobileRespModel.fromJson(json), ApiConsts.changeMobileNoOTPRequest, postParams, token: t);
  }

  @override
  Future<ConfirmMobileRespModel> changeMobileNo(String userToken, String userOTP) async {
    var postParams = {
      "userToken": userToken,
      "userOTP": userOTP,
    };
    String t = AppState().getUser.data!.accessToken ?? "";
    return await injector.get<ApiClient>().postJsonForObject((json) => ConfirmMobileRespModel.fromJson(json), ApiConsts.changeMobileNo, postParams, token: t);
  }

  @override
  Future<ChanEmailRespModel> changeEmailOTPRequest(String email, String password) async {
    var postParams = {"email": email, "password": password};
    String t = AppState().getUser.data!.accessToken ?? "";
    return await injector.get<ApiClient>().postJsonForObject((json) => ChanEmailRespModel.fromJson(json), ApiConsts.changeEmailOTPRequest, postParams, token: t);
  }

  @override
  Future<ConfirmEmailRespModel> changeEmail(String userToken, String userOTP) async {
    var postParams = {"userToken": userToken, "userOTP": userOTP};
    String t = AppState().getUser.data!.accessToken ?? "";
    return await injector.get<ApiClient>().postJsonForObject((json) => ConfirmEmailRespModel.fromJson(json), ApiConsts.changeEmail, postParams, token: t);
  }

  @override
  Future<Map<String, dynamic>> updateUserInfo(String firstName, String lastName, String? city) async {
    var postParams = {"userID": "${AppState().getUser.data!.userInfo!.userId}", "firstName": "${firstName}", "lastName": "${lastName}", "genderID": 1, "cityID": city ?? 1};
    String t = AppState().getUser.data!.accessToken ?? "";
    return await injector.get<ApiClient>().postJsonForObject((json) => json, ApiConsts.userUpdate, postParams, token: t);
  }

  @override
  Future<VerifyEmailRespModel> emailVerify(String email, String userID) async {
    var postParams = {
      // "email": email,
      // "userID": userID,
      "email": AppState().getUser.data!.userInfo!.email ?? "",
      "userID": AppState().getUser.data!.userInfo!.userId ?? "",
    };

    String t = AppState().getUser.data!.accessToken ?? "";
    return await injector.get<ApiClient>().postJsonForObject((json) => VerifyEmailRespModel.fromJson(json), ApiConsts.emailVerify, postParams, token: t);
  }

  @override
  Future<GenericRespModel> emailVerifyOTPVerify(String userToken, String userOTP) async {
    var postParams = {"userToken": userToken, "userOTP": userOTP};

    String t = AppState().getUser.data!.accessToken ?? "";
    return await injector.get<ApiClient>().postJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.emailVerifyOTPVerify, postParams, token: t);
  }

  @override
  Future<ImageResponse> updateUserImage(String image) async {
    var postParams = {"userID": AppState().getUser.data!.userInfo!.userId, "userImage": image};
    // return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.ChangePassword, postParams);

    String t = AppState().getUser.data!.accessToken ?? "";
    debugPrint("token $t");
    return await injector.get<ApiClient>().postJsonForObject(
          (json) => ImageResponse.fromJson(json),
          ApiConsts.updateUserImage,
          postParams,
          token: t,
        );
  }

  @override
  Future<ImageResponse> getUserImage(String image) async {
    var postParams = {};
    // return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.ChangePassword, postParams);

    String t = AppState().getUser.data!.accessToken ?? "";
    debugPrint("token $t");
    return await injector.get<ApiClient>().postJsonForObject((json) => ImageResponse.fromJson(json), ApiConsts.updateUserImage, postParams, token: t);
  }

  @override
  Future<String> updateUserToken() async {
    String token = await SharedPrefManager.getUserToken();
    String refreshToken = await SharedPrefManager.getRefreshToken();
    RefreshToken refresh = await refreshTokenAPI(token, refreshToken);
    SharedPrefManager.setUserToken(refresh.data!.accessToken ?? "");
    SharedPrefManager.setRefreshToken(refresh.data!.refreshToken ?? "");
    String mdata = await SharedPrefManager.getData();
    UserInfo info = UserInfo.fromJson(jsonDecode(mdata));
    User user = User();
    user.data = UserData(accessToken: refresh.data!.accessToken ?? "", refreshToken: refresh.data!.refreshToken ?? "", userInfo: info);

    AppState().setUser = user;
    return refresh.data!.accessToken ?? "";
  }

  Future<Response> logoutUser() async {
    String t = AppState().getUser.data!.accessToken ?? "";
    var postParams = {"token": AppState().getUser.data!.accessToken ?? ""};
    return await injector.get<ApiClient>().postJsonForResponse(ApiConsts.logoutUser, postParams, token: t);
  }
}
