import { cloneDeep } from 'lodash-es'
import { createDefu } from 'defu'
import router from '@main/router'
import { loginApi } from '@main/api/modules/login'
import settingsDefault from '@main/settings'
import menuApi from '@main/api/modules/menu'
import { tenantApi } from '@main/api/modules/tenant'
import { userApi } from '@main/api/modules/user'
import useSettingsStore from './settings'
import useTabbarStore from './tabbar'
import useRouteStore from './route'
import useMenuStore from './menu'
import useSocketStore from './socket'
import type { Settings } from '#/global'

const useUserStore = defineStore(
  // 唯一ID
  'user',
  () => {
    const settingsStore = useSettingsStore()
    const tabbarStore = useTabbarStore()
    const routeStore = useRouteStore()
    const menuStore = useMenuStore()
    const socketStore = useSocketStore()

    const account = ref(ikStore.local.getItem(ELocal.ACCOUNT) ?? '')
    const token = ref(ikStore.local.getItem(ELocal.TOKEN) ?? '')
    const failure_time = ref(ikStore.local.getItem(ELocal.FAILURE_TIME) ?? '')
    const permissions = ref<string[]>([])
    const userInfo = ref(ikStore.local.getItem(ELocal.USER_INFO) ?? '')
    const pwdVisible = ref(Boolean(Number(ikStore.local.getItem(ELocal.PWD_VISIBLE) || 0)))
    const pwdType = ref('timeout')
    const settingId = ref(ikStore.local.getItem(ELocal.SETTING_ID) ?? '')
    const tenant = ref(ikStore.local.getItem(ELocal.TENANT) ?? '')
    const showTenant = ref(false)

    const organiza = ref(ikStore.local.getItem(ELocal.ORGANIZA) || {
      select: '',
      list: [],
    })

    const isLogin = computed(() => {
      if (token.value) {
        return true
      }
      return false
    })

    // 获取用户租户信息
    async function queryTenant() {
      if (!token.value) {
        return null
      }
      const res = await tenantApi.queryTenantList()
      return res
    }
    // 获取用户信息 通过
    async function getUserInfo(id: string) {
      if (!token.value) {
        return null
      }
      const { success, data } = await loginApi.getUserInfo(id)
      if (success) {
        userInfo.value = data
        if (!account.value) {
          account.value = data.name
        }
        data && ikStore.local.setItem(ELocal.USER_INFO, data)
        // 用户组织数据
        organiza.value = {
          select: data.organizationIds?.[0] || '',
          list: data.organizations,
        }
        ikStore.local.setItem(ELocal.ORGANIZA, organiza.value)
        try {
          // 创建socket连接
          socketStore.createSocket()
        }
        catch (error) {
          throw new Error(error)
        }
      }
    }
    // 获取字典
    async function getAllDiction() {
      const { success, msg, data } = await menuApi.getAllDiction()
      if (success) {
        const fa: Set<string> = new Set(
          data.map((item: { dictCode: string }) => item?.dictCode),
        )
        for (const i of fa) {
          data.push({ id: i, name: i })
        }

        const dict: { [key: string]: any } = {}
        const tree = ikTree.listToTree(data, { id: 'id', pid: 'dictCode' })
        for (const i of fa) {
          dict[i] = tree.find((f: { id: string }) => f.id === i)?.children
        }
        ikStore.local.setItem(ELocal.DICTIONARY, dict)
      }
      else { useMessage().msgWarning(msg) }
    }

    const handleLoginRes = async (res: { msg: string, data: any, success: boolean }, type: string) => {
      const { msg, data, success } = res
      if (!success) {
        return
      }

      if (success) {
        // 系统右上角用户名
        account.value = data.name
        token.value = data.token
        failure_time.value = data.expire
      }
      // 更新提示修改密码框状态
      updatePwdVisible(data?.passwordExpired || false)
      if (success && type === ELoginType.密码登录) {
        await ikStore.local.setItem(ELocal.TOKEN, data.token)
        ikStore.local.setItem(ELocal.ACCOUNT, data.name)
        ikStore.local.setItem(
          ELocal.FAILURE_TIME,
          new Date().getTime() + Number.parseInt(data.expire || 99999) * 1000 * 60,
        )
        useMessage().msgSuccess(msg)
      }
      // 获取页面CSS灰度值（特殊时期页面置灰）
      loginApi.getPageCssFilter().then((res: any) => {
        ikStore.local.setItem(ELocal.GRRY, res?.data ?? 1)
      })
      // 获取用户详细信息userInfo
      await getUserInfo(data.id)
      return res
    }

    const buildTokenAutoLoginRes = (token: string | undefined) => {
      return {
        code: 200,
        success: true,
        msg: '登录成功',
        pages: 0,
        total: 0,
        data: {
          name: '',
          token,
          expire: 0,
        },
      }
    }

    // 登录
    async function login(
      param: {
        account?: string
        password?: string
        phone?: string
        captcha?: string
        token?: string
      },
      type: string,
    ) {
      let res: ApiModel = {
        msg: '',
        data: null,
        code: 0,
        pages: 0,
        success: false,
        total: 0,
      }
      switch (type) {
        case ELoginType.Token自动登录:
          res = buildTokenAutoLoginRes(param.token)
          break
        case ELoginType.密码登录:
          res = await loginApi.login(
            {
              credentialName: param.account,
              password: passwordEncry(
                param.password || '',
                '1234567890000000',
                {
                  encode: 'hex',
                },
              ).AES.encrypt(),
            },
            {
              headers: {
                'X-PASSWORD-ENCRYPT': 'encrypt',
              },
            },
          )
          break
        case ELoginType.短信登录:
          // 短信登录参数
          res = await loginApi.login(
            {
              phone: param.phone,
              smsVerifyCode: param.captcha,
            },
            {
              headers: {
                'X-PASSWORD-ENCRYPT': 'encrypt',
              },
            },
          )
          break
        case ELoginType.微信登录:
          // 微信登录参数
          res = await loginApi.login(
            {
              wechatMiniOpenId: '',
            },
            {},
          )
          break
        case ELoginType.钉钉登录:
          // 钉钉登录参数
          break
        default:
          break
      }
      return handleLoginRes(res, type)
    }
    // 登出
    async function logout(redirect = router.currentRoute.value.fullPath) {
      ikStore.local.removeItem('account')
      ikStore.local.removeItem('token')
      ikStore.local.removeItem('avatar')
      account.value = ''
      token.value = ''
      permissions.value = []
      tabbarStore.clean()
      routeStore.removeRoutes()
      // menuStore.setActived(0)
      router.push({
        name: 'login',
        query: {
          ...(router.currentRoute.value.path !== settingsStore.settings.home.fullPath && router.currentRoute.value.name !== 'login' && { redirect }),
        },
      })
    }

    // 修改密码
    async function editPassword(data: {
      password: string
      newpassword: string
    }) {
      await apiUser.passwordEdit(data)
    }

    // 框架已将可提供给用户配置的选项提取出来，请勿新增其他选项，不需要的选项可以在这里注释掉
    const preferences = ref<Settings.all>({
      app: {
        colorScheme: settingsDefault.app.colorScheme,
        lightTheme: settingsDefault.app.lightTheme,
        darkTheme: settingsDefault.app.darkTheme,
        enableProgress: settingsDefault.app.enableProgress,
      },
      menu: {
        menuMode: settingsDefault.menu.menuMode,
        isRounded: settingsDefault.menu.isRounded,
        menuActiveStyle: settingsDefault.menu.menuActiveStyle,
        switchMainMenuAndPageJump: settingsDefault.menu.switchMainMenuAndPageJump,
        subMenuOnlyOneHide: settingsDefault.menu.subMenuOnlyOneHide,
        subMenuUniqueOpened: settingsDefault.menu.subMenuUniqueOpened,
        subMenuCollapse: settingsDefault.menu.subMenuCollapse,
        subMenuAutoCollapse: settingsDefault.menu.subMenuAutoCollapse,
        enableSubMenuCollapseButton: settingsDefault.menu.enableSubMenuCollapseButton,
      },
      layout: {
        widthMode: settingsDefault.layout.widthMode,
      },
      mainPage: {
        enableTransition: settingsDefault.mainPage.enableTransition,
        transitionMode: settingsDefault.mainPage.transitionMode,
      },
      topbar: {
        mode: settingsDefault.topbar.mode,
        switchTabbarAndToolbar: settingsDefault.topbar.switchTabbarAndToolbar,
      },
      tabbar: {
        style: settingsDefault.tabbar.style,
        enableIcon: settingsDefault.tabbar.enableIcon,
        enableMemory: settingsDefault.tabbar.enableMemory,
      },
      toolbar: {
        breadcrumb: settingsDefault.toolbar.breadcrumb,
        navSearch: settingsDefault.toolbar.navSearch,
        fullscreen: settingsDefault.toolbar.fullscreen,
        pageReload: settingsDefault.toolbar.pageReload,
        colorScheme: settingsDefault.toolbar.colorScheme,
        layout: settingsDefault.toolbar.layout,
      },
      breadcrumb: {
        style: settingsDefault.breadcrumb.style,
        enableMainMenu: settingsDefault.breadcrumb.enableMainMenu,
      },
    })
    // 此处没有使用 lodash 的 defaultsDeep 函数，而是基于 defu 库自定义了一个函数，只合并 settings 中有的属性，而不是全部合并，这样做的目的是为了排除用户历史遗留的偏好配置
    const customDefaultsDeep = createDefu((obj, key, value) => {
      if (obj[key] === undefined) {
        delete obj[key]
        return true
      }
      if (Array.isArray(obj[key]) && Array.isArray(value)) {
        obj[key] = value
        return true
      }
    })
    // isPreferencesUpdating 用于防止循环更新
    let isPreferencesUpdating = false
    watch(preferences, (val) => {
      if (!settingsStore.settings.userPreferences.enable) {
        return
      }
      if (!isPreferencesUpdating) {
        isPreferencesUpdating = true
        settingsStore.updateSettings(cloneDeep(val))
      }
      else {
        isPreferencesUpdating = false
      }
      updatePreferences(cloneDeep(val))
    }, {
      deep: true,
    })
    watch(() => settingsStore.settings, (val) => {
      if (!settingsStore.settings.userPreferences.enable) {
        return
      }
      if (!isPreferencesUpdating) {
        isPreferencesUpdating = true
        preferences.value = customDefaultsDeep(val, preferences.value)
      }
      else {
        isPreferencesUpdating = false
      }
    }, {
      deep: true,
    })
    // isPreferencesInited 用于防止初始化时触发更新
    let isPreferencesInited = false
    // 获取偏好设置
    async function getPreferences() {
      let data: Settings.all = {}
      if (settingsStore.settings.userPreferences.storageTo === 'local') {
        if (ikStore.local.has('userPreferences')) {
          data = JSON.parse(ikStore.local.getItem('userPreferences') as string)[account.value] || {}
        }
      }
      else if (settingsStore.settings.userPreferences.storageTo === 'server') {
        const res = await apiUser.preferences()
        data = JSON.parse(res.data.preferences || '{}') as Settings.all
      }
      preferences.value = customDefaultsDeep(data, preferences.value)
    }
    // 更新偏好设置
    async function updatePreferences(data: Settings.all = {}) {
      if (!isPreferencesInited) {
        isPreferencesInited = true
        return
      }
      if (settingsStore.settings.userPreferences.storageTo === 'local') {
        const userPreferencesData = ikStore.local.has('userPreferences') ? JSON.parse(ikStore.local.getItem('userPreferences') as string) : {}
        userPreferencesData[account.value] = data
        ikStore.local.setItem('userPreferences', JSON.stringify(userPreferencesData))
      }
      else if (settingsStore.settings.userPreferences.storageTo === 'server') {
        await apiUser.preferencesEdit(JSON.stringify(data))
      }
    }
    // 更新密码框状态
    function updatePwdVisible(bool: boolean, type = 'timeout') {
      pwdType.value = type
      pwdVisible.value = Boolean(bool)
      ikStore.local.setItem(ELocal.PWD_VISIBLE, bool ? 1 : 0)
    }
    const queryAllDic = async () => {
      try {
        await getUserSetting()
        await getAllDiction()
      }
      catch (error) {
        useLog().warn(error)
      }
    }
    // 获取并应用用户配置
    async function getUserSetting() {
      const { success, data, msg } = await userApi.getSetting()
      if (success && data?.configInfoList?.length) {
        const dataValue = data?.configInfoList?.find((item: any) => item.type === 'THEME')
        const sett = JSON.parse(dataValue?.value || '')
        if (!paramType.isObject(sett)) {
          console.warn('用户配置错误', sett)
          return
        }
        settingsStore.updateSettings(sett)
        settingId.value = dataValue?.id
        ikStore.local.setItem(ELocal.SETTING, sett)
      }
      !success && console.warn(msg)
    }
    // 保存用户配置
    async function setUserSetting(config: {
      id?: string
      userId: string
      type: 'THEME' | 'LANGUAGE'
      value: string
    }) {
      const { success, msg } = await userApi.setSetting({
        ...config,
        global: false,
      })
      !success && console.warn(msg)
      try {
        ikStore.local.setItem(ELocal.SETTING, JSON.parse((config as any)?.configInfoList?.find((item: any) => item.type === 'THEME')?.value || ''))
      }
      catch (error) {
      }
    }
    function clearCache() {
      try {
        routeStore.removeRoutes()
        // routeStore.isGenerate = false
        ikStore.local.removeItem('account')
        ikStore.local.removeItem('token')
        ikStore.local.removeItem('failure_time')
        ikStore.local.removeItem('user_info')
        ikStore.local.removeItem('tenant')
        account.value = ''
        token.value = ''
        failure_time.value = ''
        permissions.value = []
        tabbarStore.clean()
        menuStore.setActived(0)
      }
      catch (error) {
        throw new Error(error as string)
      }
    }
    const getLoginUser = async () => {
      await tenantApi.getLoginUser()
    }
    const autoLoginNext = async () => {
      const res = await queryTenant()
      const tenantList = ref<any>(null)
      if (res?.success) {
        tenantList.value = res?.data || null
        if (res?.data?.length === 1) {
          if (res?.data[0].normal) {
            ikStore.local.setItem(ELocal.TENANT, res.data[0])
            tenant.value = res?.data[0]
            await getLoginUser()
            await queryAllDic()
            if (!showTenant.value) {
              // router.push(redirect.value)
              return
            }
          }
          else {
            showTenant.value = true
          }
        }
        if (res?.data?.tenantList?.length > 1) {
          const loginTenant = res?.data?.tenantList.find(
            (item: any) => item.recent === true,
          )
          if (loginTenant) {
            tenant.value = loginTenant
            ikStore.local.setItem(ELocal.TENANT, loginTenant)
            await getLoginUser()
            await queryAllDic()
            if (!showTenant.value) {
              // router.push(redirect.value)
              return
            }
          }
        }
        showTenant.value = true
      }
      else {
        // res?.msg && msgError(res?.msg)
        showTenant.value = false
      }
    }
    async function autoLogin(token: string, to: any) {
      const res = await login({ token }, ELoginType.Token自动登录)
      await autoLoginNext()
      if (res?.success) {
        router.push(to.path)
      }
    }

    return {
      account,
      token,
      permissions,
      isLogin,
      userInfo,
      pwdVisible,
      pwdType,
      tenant,
      showTenant,
      organiza,
      login,
      autoLogin,
      logout,
      editPassword,
      updatePwdVisible,
      clearCache,
      getUserSetting,
      setUserSetting,
      queryTenant,
      getAllDiction,
      queryAllDic,
    }
  },
)

export default useUserStore
