package com.gh.gamecenter.login.user;

import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.TextUtils;

import androidx.annotation.Nullable;

import com.alibaba.android.arouter.launcher.ARouter;
import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.RouteConsts;
import com.gh.gamecenter.common.eventbus.EBShowDialog;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.common.utils.DeviceUtils;
import com.gh.gamecenter.common.utils.EnvHelper;
import com.gh.gamecenter.core.provider.IErrorHelperProvider;
import com.gh.gamecenter.core.provider.IReservationRepositoryProvider;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.login.HaloApp;
import com.gh.gamecenter.login.entity.LoginTokenEntity;
import com.gh.gamecenter.login.entity.TokenEntity;
import com.gh.gamecenter.login.entity.UserInfoEntity;
import com.gh.gamecenter.login.retrofit.ApiService;
import com.gh.gamecenter.login.retrofit.RetrofitManager;
import com.lightgame.utils.Utils;

import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;

import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.HttpException;

/**
 * Created by khy on 29/11/17.
 */

public class UserManager {

    private SharedPreferences mSp;

    @Nullable
    private UserInfoEntity mUserInfoEntity;
    private LoginTokenEntity mLoginTokenEntity;

    private String deviceId;

    public static UserManager getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private UserManager() {
        mSp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance());
        deviceId = mSp.getString(Constants.DEVICE_KEY, "");
    }

    public LoginTokenEntity getLoginTokenEntity() {
        return mLoginTokenEntity;
    }

    public void setLoginTokenEntity(LoginTokenEntity loginTokenEntity) {
        mLoginTokenEntity = loginTokenEntity;
    }

    @Nullable
    public UserInfoEntity getUserInfoEntity() {
        return mUserInfoEntity;
    }

    public void setUserInfoEntity(UserInfoEntity userInfoEntity) {
        mUserInfoEntity = userInfoEntity;
        MetaUtil.INSTANCE.refreshMeta();
    }

    public String getToken() {
        if (mLoginTokenEntity != null && mLoginTokenEntity.getAccessToken() != null) {
            return mLoginTokenEntity.getAccessToken().getValue();
        }
        return null;
    }

    public boolean isLoggedIn() {
        return !TextUtils.isEmpty(getToken());
    }

    public boolean isAuth() {
        return mUserInfoEntity != null && mUserInfoEntity.getIdCard() != null && !TextUtils.isEmpty(mUserInfoEntity.getIdCard().getId());
    }

    public String getUserId() {
        if (mUserInfoEntity != null) {
            return mUserInfoEntity.getUserId();
        }
        return "";
    }

    public String getDeviceId() {
        if (TextUtils.isEmpty(deviceId)) {
            deviceId = mSp.getString(Constants.DEVICE_KEY, "");
        }
        return deviceId;
    }

    public void logout() {
        mUserInfoEntity = null;
        mLoginTokenEntity = null;
    }

    public synchronized void refreshToken(String accessToken, final refreshCallBack callBack) {

        // LoginTokenEntity 为空,可能已经退出登录
        LoginTokenEntity tokenEntity = getLoginTokenEntity();
        if (tokenEntity == null) {
            callBack.onLoginFailure(null);
            return;
        }

        // 对比AccessToken 如果接口传的token与UserManager的token不一致 则已被刷新过
        if (!accessToken.equals(tokenEntity.getAccessToken().getValue())) {
            callBack.onLogin();
            return;
        }

        // 判断RefreshToken是否过期
        TokenEntity refreshToken = tokenEntity.getRefreshToken();
        if (refreshToken.getExpire() < Utils.getTime(HaloApp.getInstance())) {
            Utils.toast(HaloApp.getInstance(), "账号过期，请重新登录!");
            UserRepository.getInstance().logout();
            callBack.onLoginFailure(null);
            return;
        }

        RequestBody body = null;
        try {
            JSONObject device = DeviceUtils.getLoginDevice(HaloApp.getInstance());
            JSONObject content = new JSONObject();
            content.put("refresh_token", refreshToken.getValue());
            content.put("device", device);
            body = RequestBody.create(MediaType.parse("application/json"), content.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
        getApiService()
                .refreshToken(EnvHelper.getHost() + "tokens:refresh", body)
                .subscribe(new Response<LoginTokenEntity>() {
                    @Override
                    public void onResponse(LoginTokenEntity response) {
                        super.onResponse(response);

                        saveLoginToken(response);

                        refreshUserInfo(callBack);

                        // 更新用户预约的游戏列表
                        IReservationRepositoryProvider reservationRepository = (IReservationRepositoryProvider) ARouter.getInstance().build(RouteConsts.provider.reservationRepository).navigation();
                        reservationRepository.refreshReservations();

                        refreshUserRegulationTestStatus();
                    }

                    @Override
                    public void onFailure(HttpException e) {
                        super.onFailure(e);
                        String errorMessage = "null";
                        if (e != null && (e.code() == 401 || e.code() == 403 || e.code() == 400)) {
                            int code = -1;
                            try {
                                errorMessage = e.response().errorBody().string();
                                JSONObject content = new JSONObject(errorMessage);
                                code = content.getInt("code");
                                if (code == 400802) { // 其他设备登录了该账号
                                    EventBus.getDefault().post(new EBShowDialog(BaseActivity.LOGIN_EXCEPTION, errorMessage)); // 打开提示框
                                }

                                if (code == 400401 || code == 400802) { // 自动注销
                                    UserRepository.getInstance().logout();
                                }

                                if (code == 403401 || code == 403404) {
                                    UserRepository.getInstance().logout();
                                    IErrorHelperProvider errorHelper = (IErrorHelperProvider) ARouter.getInstance().build(RouteConsts.provider.errorHelper).navigation();
                                    errorHelper.handleLoginError(HaloApp.getInstance().getApplicationContext(), e, "", false);
                                }
                            } catch (Exception e1) {
                                e1.printStackTrace();
                            }
                        } else {
                            try {
                                if (e != null) {
                                    errorMessage = e.response().errorBody().string();
                                }
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                        }

                        if (callBack != null) {
                            callBack.onLoginFailure(errorMessage);
                        }
                    }
                });
    }

    @SuppressLint("CheckResult")
    public void refreshUserRegulationTestStatus() {
        if ("on".equals(SPUtils.getString(Constants.SP_REGULATION_TEST_STATUS, "off"))) {
            getApiService().getUserRegulationTestStatus(UserManager.getInstance().getUserId())
                    .subscribeOn(Schedulers.io())
                    .subscribe(new BiResponse<ResponseBody>() {
                        @Override
                        public void onSuccess(ResponseBody data) {
                            try {
                                JSONObject object = new JSONObject(data.string());
                                SPUtils.setString(Constants.SP_REGULATION_TEST_PASS_STATUS, object.getString("status"));
                            } catch (Throwable e) {
                                e.printStackTrace();
                            }
                        }
                    });
        }
    }

    private void refreshUserInfo(final refreshCallBack callBack) {
        getApiService()
                .getRetryUserInfo(EnvHelper.getHost() + "tokens:validate", "retry")
                .subscribe(new Response<UserInfoEntity>() {
                    @Override
                    public void onResponse(UserInfoEntity response) {
                        super.onResponse(response);
                        saveUserInfo(response);

                        if (callBack != null) {
                            callBack.onLogin();
                        }

                    }

                    @Override
                    public void onFailure(HttpException e) {
                        super.onFailure(e);
                        String string = "";
                        try {
                            string = e.response().errorBody().string();
                        } catch (Exception e1) {
                            e1.printStackTrace();
                        }
                        if (callBack != null) {
                            callBack.onLoginFailure(string);
                        }

                    }
                });
    }

    private void saveLoginToken(final LoginTokenEntity tokenEntity) {
        LoginTokenEntity loginTokenEntity = getLoginTokenEntity();
        if (loginTokenEntity != null) {
            tokenEntity.setLoginType(loginTokenEntity.getLoginType());
            tokenEntity.setId(loginTokenEntity.getId());
        }
        setLoginTokenEntity(tokenEntity);
        SPUtils.setString(mSp, Constants.USER_TOKEN_KEY, GsonUtils.toJson(tokenEntity));
    }

    private void saveUserInfo(final UserInfoEntity userInfo) {
        setUserInfoEntity(userInfo);
        SPUtils.setString(mSp, Constants.USER_INFO_KEY, GsonUtils.toJson(userInfo));
    }

    private ApiService getApiService() {
        return RetrofitManager.getInstance().getApi();
    }

    public boolean userShouldTakeRegulationBaseOnLastRemind() {
        long lastRemindTime = SPUtils.getLong(Constants.SP_REGULATION_TEST_LAST_REMIND_TIME + UserManager.getInstance().getUserId(), 0);

        if (lastRemindTime == 0
                || lastRemindTime - System.currentTimeMillis() > 7 * 24 * 3600 * 1000) {
            if (isLoggedIn()
                    && "on".equals(SPUtils.getString(Constants.SP_REGULATION_TEST_STATUS))
                    && !"pass".equals(SPUtils.getString(Constants.SP_REGULATION_TEST_PASS_STATUS))) {
                SPUtils.setLong(Constants.SP_REGULATION_TEST_LAST_REMIND_TIME + UserManager.getInstance().getUserId(), System.currentTimeMillis());
                return true;
            }
        }
        return false;
    }

    public boolean userShouldTakeRegulationTest() {
        return isLoggedIn()
                && "on".equals(SPUtils.getString(Constants.SP_REGULATION_TEST_STATUS))
                && !"pass".equals(SPUtils.getString(Constants.SP_REGULATION_TEST_PASS_STATUS));
    }

    public interface refreshCallBack {
        void onLogin();

        void onLoginFailure(@Nullable String errorMessage);
    }

    private static class SingletonHolder {
        private static final UserManager INSTANCE = new UserManager();
    }
}
