import { defineStore } from 'pinia';
import { ref } from 'vue';
import { CACHE_KEY } from '@/constants/index';
// @ts-ignore 因为 utils 可能还没做完整的 ts 设置
import { Local, Session } from '@/utils/storage';
import { useLoginApi } from '@/api/system/login';
import { useSystemApi } from '@/api/system/index';
import { useUserApi } from '@/api/user/index';
import type { LoginParams, UserInfo } from '@/types/user';
import { sm3 } from 'sm-crypto';
import to from 'await-to-js';

const loginApi = useLoginApi();
const systemApi = useSystemApi();
const userApi = useUserApi();

export const useUserStore = defineStore('user', () => {
  // ==================== State ====================
  const token = ref<string>(Local.get(CACHE_KEY.TOKEN) || '');
  const userInfo = ref<UserInfo>(Local.get(CACHE_KEY.USER_INFO) || ({} as UserInfo));
  const perms = ref<string[]>(Local.get(CACHE_KEY.PERMS) || []);
  const roles = ref<any[]>(Local.get(CACHE_KEY.ROLES) || []);
  const configSetting = ref<any>({});

  // 页面请求加载状态
  const loadings = {
    loginLoading: ref<boolean>(false),
    isLogining: ref<boolean>(false),
    fetchUserInfoLoading: ref<boolean>(false),
    logoutLoading: ref<boolean>(false),
  } as const;

  // ==================== Actions ====================

  /**
   * 设置请求加载状态
   */
  function setRequestLoading(field: keyof typeof loadings, value: boolean) {
    loadings[field].value = value;
  }

  /**
   * 检查验证码配置
   */
  async function checkCaptcha() {
    const [err, res] = await to(systemApi.getEntityMapByKeys({ configKeys: ['isCaptcha'] }));
    if (err) return;
    if (res?.data) {
      configSetting.value = res.data;
    }
  }

  /**
   * 清理用户状态和本地缓存
   */
  function clearUserStatus() {
    token.value = '';
    roles.value = [];
    perms.value = [];
    userInfo.value = {} as UserInfo;

    Local.remove(CACHE_KEY.TOKEN);
    Local.remove(CACHE_KEY.USER_INFO);
    Local.remove(CACHE_KEY.PERMS);
    Local.remove(CACHE_KEY.ROLES);
    Session.clear();
  }

  /**
   * 用户登录
   */
  async function login(loginParams: LoginParams) {
    setRequestLoading('loginLoading', true);

    // 使用 sm3 加密密码
    const encryptedPassword = loginParams.password ? sm3(loginParams.password) : '';

    const [err, res] = await to(
      loginApi.signIn({
        userName: loginParams.userName,
        password: encryptedPassword,
        idValueC: loginParams.idValueC,
        idKeyC: loginParams.idKeyC,
        saltValue: loginParams.saltValue,
      })
    );

    setRequestLoading('loginLoading', false);

    if (err) {
      return Promise.reject(err);
    }

    const resToken = res?.data?.token;
    if (resToken) {
      token.value = resToken;
      Local.set(CACHE_KEY.TOKEN, resToken);
      // 登录成功后主动获取用户信息
      await fetchUserInfo();
    }

    return res;
  }

  /**
   * 钉钉免登
   */
  async function dingTalkLogin(code: string) {
    setRequestLoading('isLogining', true);
    
    const [err, res] = await to(loginApi.dingTalkLogin({ code }));
    
    setRequestLoading('isLogining', false);
    
    if (err) {
      return Promise.reject(err);
    }
    
    const resToken = res?.data?.token;
    if (resToken) {
      token.value = resToken;
      Local.set(CACHE_KEY.TOKEN, resToken);
      // 登录成功后主动获取用户信息
      await fetchUserInfo();
    }
    
    return res;
  }

  /**
   * 获取用户信息
   */
  async function fetchUserInfo() {
    setRequestLoading('fetchUserInfoLoading', true);

    const [err, res] = await to(userApi.getUserByUserName());

    setRequestLoading('fetchUserInfoLoading', false);

    if (err) {
      return Promise.reject(err);
    }

    // 解决解构变量和 ref 变量重名问题
    const {
      userInfo: resUserInfo,
      perms: resPerms,
      roles: resRoles,
    } = res?.data || {};

    userInfo.value = resUserInfo || ({} as UserInfo);
    perms.value = resPerms || [];
    roles.value = resRoles || [];

    Local.set(CACHE_KEY.USER_INFO, userInfo.value);
    Local.set(CACHE_KEY.PERMS, perms.value);
    Local.set(CACHE_KEY.ROLES, roles.value);
  }

  /**
   * 用户登出
   */
  async function logout() {
    setRequestLoading('logoutLoading', true);

    const [err] = await to(loginApi.signOut());

    setRequestLoading('logoutLoading', false);

    // 即便接口报错也要清空本地缓存和状态
    clearUserStatus();

    if (err) {
      console.warn('退出登录异常', err);
    }
  }

  return {
    ...loadings,
    token,
    userInfo,
    perms,
    roles,
    configSetting,
    login,
    dingTalkLogin,
    fetchUserInfo,
    logout,
    clearUserStatus,
    setRequestLoading,
    checkCaptcha,
  };
});
