/* eslint-disable brace-style */ // 原因：unibest 官方维护的代码，尽量不要大概，避免难以合并
import type {
  AuthLoginReqVO,
  AuthRegisterReqVO,
  AuthSmsLoginReqVO,
  ILoginForm,
} from '@/api/login'
import type { IAuthLoginRes } from '@/api/types/login'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue' // 修复：导入 computed
import { useToast } from 'wot-design-uni'
import {
  login as _login,
  logout as _logout,
  refreshToken as _refreshToken,
  wxLogin as _wxLogin,
  getWxCode,
  register,
  smsLogin,
} from '@/api/login'
import { isDoubleTokenRes, isSingleTokenRes } from '@/api/types/login'
import { isDoubleTokenMode } from '@/utils'
import { useDictStore } from './dict'
import { useUserStore } from './user'

// 初始化状态
const tokenInfoState = isDoubleTokenMode
  ? {
      accessToken: '',
      // accessExpiresIn: 0,
      refreshToken: '',
      // refreshExpiresIn: 0,
      expiresTime: 0,
    }
  : {
      token: '',
      expiresIn: 0,
    }

export const useTokenStore = defineStore(
  'token',
  () => {
    const toast = useToast()
    // 定义用户信息
    const tokenInfo = ref<IAuthLoginRes>({ ...tokenInfoState })
    // 设置用户信息
    const setTokenInfo = (val: IAuthLoginRes) => {
      tokenInfo.value = val

      // 计算并存储过期时间
      const now = Date.now()
      if (isSingleTokenRes(val)) {
        // 单token模式
        const expireTime = now + val.expiresIn * 1000
        uni.setStorageSync('accessTokenExpireTime', expireTime)
      }
      else if (isDoubleTokenRes(val)) {
        // 双token模式
        const accessExpireTime = val.expiresTime
        // const refreshExpireTime = now + val.refreshExpiresIn * 1000
        uni.setStorageSync('accessTokenExpireTime', accessExpireTime)
        // uni.setStorageSync('refreshTokenExpireTime', refreshExpireTime)
        // add by 芋艿：目前后端没有返回 refreshToken 的过期时间，所以这里暂时不存储 refreshToken 过期时间
      }
    }

    /**
     * 判断token是否过期
     */
    const isTokenExpired = computed(() => {
      if (!tokenInfo.value) {
        return true
      }

      const now = Date.now()
      const expireTime = uni.getStorageSync('accessTokenExpireTime')

      if (!expireTime)
        return true
      return now >= expireTime
    })

    /**
     * 判断refreshToken是否过期
     */
    const isRefreshTokenExpired = computed(() => {
      if (!isDoubleTokenMode)
        return true

      // const now = Date.now()
      // const refreshExpireTime = uni.getStorageSync('refreshTokenExpireTime')
      //
      // if (!refreshExpireTime)
      //   return true
      // return now >= refreshExpireTime
      // add by 芋艿：目前后端没有返回 refreshToken 的过期时间，所以这里暂时不做过期判断，先全部返回 false 非过期
      return false
    })

    /**
     * 登录成功后处理逻辑
     * @param tokenInfo 登录返回的token信息
     */
    async function _postLogin(tokenInfo: IAuthLoginRes) {
      // 设置认证信息
      setTokenInfo(tokenInfo)
      // 获取用户信息
      const userStore = useUserStore()
      await userStore.fetchUserInfo()
      // add by 芋艿：加载字典数据（异步）
      const dictStore = useDictStore()
      dictStore.loadDictCache().then()
    }

    /**
     * 用户登录：账号登录、注册登录、短信登录、三方登录等
     * 有的时候后端会用一个接口返回token和用户信息，有的时候会分开2个接口，一个获取token，一个获取用户信息
     * （各有利弊，看业务场景和系统复杂度），这里使用2个接口返回的来模拟
     * @param loginForm 登录参数
     * @returns 登录结果
     */
    const login = async (loginForm: ILoginForm) => {
      let typeName = ''
      try {
        let res: IAuthLoginRes
        switch (loginForm.type) {
          case 'register': {
            res = await register(loginForm as AuthRegisterReqVO)
            typeName = '注册'
            break
          }
          case 'sms': {
            res = await smsLogin(loginForm as AuthSmsLoginReqVO)
            typeName = '注册'
            break
          }
          default: {
            res = await _login(loginForm as AuthLoginReqVO)
            typeName = '登录'
          }
        }
        // console.log('普通登录-res: ', res)
        await _postLogin(res)
        // 注释 by 芋艿：使用 wd-toast 替代
        // uni.showToast({
        //   title: `${typeName}成功`,
        //   icon: 'success',
        // })
        toast.success(`${typeName}成功`)
        return res
      }
      catch (error) {
        console.error(`${typeName}失败:`, error)
        // 注释 by 芋艿：避免覆盖 http.ts 中的错误提示
        // uni.showToast({
        //   title: `${typeName}失败，请重试`,
        //   icon: 'error',
        // })
        throw error
      }
    }

    /**
     * 微信登录
     * 有的时候后端会用一个接口返回token和用户信息，有的时候会分开2个接口，一个获取token，一个获取用户信息
     * （各有利弊，看业务场景和系统复杂度），这里使用2个接口返回的来模拟
     * @returns 登录结果
     */
    const wxLogin = async () => {
      try {
        // 获取微信小程序登录的code
        const code = await getWxCode()
        console.log('微信登录-code: ', code)
        const res = await _wxLogin(code)
        console.log('微信登录-res: ', res)
        await _postLogin(res)
        // 注释 by 芋艿：使用 wd-toast 替代
        // uni.showToast({
        //   title: '登录成功',
        //   icon: 'success',
        // })
        toast.success('登录成功')
        return res
      }
      catch (error) {
        console.error('微信登录失败:', error)
        // 注释 by 芋艿：使用 wd-toast 替代
        // uni.showToast({
        //   title: '微信登录失败，请重试',
        //   icon: 'error',
        // })
        toast.error('微信登录失败，请重试')
        throw error
      }
    }

    /**
     * 退出登录 并 删除用户信息
     */
    const logout = async () => {
      try {
        // TODO 实现自己的退出登录逻辑
        await _logout()
      }
      catch (error) {
        console.error('退出登录失败:', error)
      }
      finally {
        // 无论成功失败，都需要清除本地token信息
        // 清除存储的过期时间
        uni.removeStorageSync('accessTokenExpireTime')
        // uni.removeStorageSync('refreshTokenExpireTime')
        console.log('退出登录-清除用户信息')
        tokenInfo.value = { ...tokenInfoState }
        uni.removeStorageSync('token')
        const userStore = useUserStore()
        userStore.clearUserInfo()
        // add by 芋艿：清空字典缓存
        const dictStore = useDictStore()
        dictStore.clearDictCache()
      }
    }

    /**
     * 刷新token
     * @returns 刷新结果
     */
    const refreshToken = async () => {
      if (!isDoubleTokenMode) {
        console.error('单token模式不支持刷新token')
        throw new Error('单token模式不支持刷新token')
      }

      try {
        // 安全检查，确保refreshToken存在
        if (!isDoubleTokenRes(tokenInfo.value) || !tokenInfo.value.refreshToken) {
          throw new Error('无效的refreshToken')
        }

        const refreshToken = tokenInfo.value.refreshToken
        const res = await _refreshToken(refreshToken)
        console.log('刷新token-res: ', res)
        setTokenInfo(res)
        return res
      }
      catch (error) {
        console.error('刷新token失败:', error)
        throw error
      }
    }

    /**
     * 获取有效的token
     * 注意：在computed中不直接调用异步函数，只做状态判断
     * 实际的刷新操作应由调用方处理
     */
    const getValidToken = computed(() => {
      // token已过期，返回空
      if (isTokenExpired.value) {
        return ''
      }

      if (!isDoubleTokenMode) {
        return isSingleTokenRes(tokenInfo.value) ? tokenInfo.value.token : ''
      }
      else {
        return isDoubleTokenRes(tokenInfo.value) ? tokenInfo.value.accessToken : ''
      }
    })

    /**
     * 检查是否有登录信息（不考虑token是否过期）
     */
    const hasLoginInfo = computed(() => {
      if (!tokenInfo.value) {
        return false
      }
      if (isDoubleTokenMode) {
        return isDoubleTokenRes(tokenInfo.value) && !!tokenInfo.value.accessToken
      }
      else {
        return isSingleTokenRes(tokenInfo.value) && !!tokenInfo.value.token
      }
    })

    /**
     * 检查是否已登录且token有效
     */
    const hasValidLogin = computed(() => {
      console.log('hasValidLogin', hasLoginInfo.value, !isTokenExpired.value)
      if (isDoubleTokenMode) {
        // add by 芋艿：双令牌场景下，以刷新令牌过期为准。而刷新令牌是否过期，通过请求时返回 401 来判断（由于后端 refreshToken 不返回过期时间）
        // 即相比下面的判断方式，去掉了“!isTokenExpired.value”
        // 如果不这么做：访问令牌过期时（刷新令牌没过期），会导致刷新界面时，直接认为是令牌过期，导致跳转到登录界面
        return hasLoginInfo.value
      }
      return hasLoginInfo.value && !isTokenExpired.value
    })

    /**
     * 尝试获取有效的token，如果过期且可刷新，则刷新token
     * @returns 有效的token或空字符串
     */
    const tryGetValidToken = async (): Promise<string> => {
      if (!getValidToken.value && isDoubleTokenMode && !isRefreshTokenExpired.value) {
        try {
          await refreshToken()
          return getValidToken.value
        }
        catch (error) {
          console.error('尝试刷新token失败:', error)
          return ''
        }
      }
      return getValidToken.value
    }

    return {
      // 核心API方法
      login,
      wxLogin,
      logout,

      // 认证状态判断（最常用的）
      hasLogin: hasValidLogin,

      // 内部系统使用的方法
      refreshToken,
      tryGetValidToken,
      validToken: getValidToken,

      // 调试或特殊场景可能需要直接访问的信息
      tokenInfo,
      setTokenInfo,
    }
  },
  {
    // 添加持久化配置，确保刷新页面后token信息不丢失
    persist: true,
  },
)
