import type { Recordable, UserInfo } from '@vben/types'

import { ref } from 'vue'
import { useRouter } from 'vue-router'

import { HOME_PATH, LOGIN_PATH } from '@vben/constants'
import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores'

import { notification } from 'ant-design-vue'
import { defineStore } from 'pinia'

import AuthApi from '#/api/core/auth'
import UserApi from '#/api/core/user'
import { $t } from '#/locales'

import { useBasicData } from './basic-data'

export const useAuthStore = defineStore('auth', () => {
  const accessStore = useAccessStore()
  const userStore = useUserStore()
  const router = useRouter()
  const { getDictionaries } = useGlobalInfo()
  const { initBasicData } = useBasicData()

  const loginLoading = ref(false)

  function getAccessToken(data: any) {
    if (typeof data === 'string') {
      return data
    }

    return (
      data?.accessToken ??
      data?.token ??
      data?.access_token ??
      data?.loginToken ??
      data?.access_token_value ??
      data?.data?.accessToken ??
      data?.data?.token
    )
  }

  async function completeLogin(
    accessToken: string,
    onSuccess?: () => Promise<void> | void,
  ) {
    let userInfo: null | UserInfo = null

    accessStore.setIsAccessChecked(false)
    accessStore.setAccessToken(accessToken)

    userInfo = await fetchUserInfo()
    if (accessStore.loginExpired) {
      accessStore.setLoginExpired(false)
    } else {
      onSuccess ? await onSuccess?.() : await router.push(HOME_PATH)
    }

    if (userInfo?.nickName) {
      notification.success({
        description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.nickName}`,
        duration: 3,
        message: $t('authentication.loginSuccess'),
      })
    }

    return userInfo
  }

  /**
   * 异步处理登录操作
   * Asynchronously handle the login process
   * @param params 登录表单数据
   * @param onSuccess 成功之后的回调函数
   */
  async function authLogin(
    params: Recordable<any>,
    onSuccess?: () => Promise<void> | void,
  ) {
    // 异步处理用户登录操作并获取 accessToken
    let userInfo: null | UserInfo = null
    try {
      loginLoading.value = true
      const accessToken = await AuthApi.login(params)

      // 如果成功获取到 accessToken
      if (accessToken) {
        userInfo = await completeLogin(accessToken, onSuccess)
      }
    } finally {
      loginLoading.value = false
    }

    return {
      userInfo,
    }
  }

  async function authWechatLogin(
    params: { code: string; state: string },
    onSuccess?: () => Promise<void> | void,
  ) {
    let userInfo: null | UserInfo = null
    let result: any

    try {
      loginLoading.value = true
      result = await AuthApi.wechatLogin(params)

      if (result?.bindRequired === true) {
        return {
          bindRequired: true,
          openid: result.openid ?? result.openId,
          result,
          userInfo,
        }
      }

      const accessToken = getAccessToken(result)
      if (accessToken) {
        userInfo = await completeLogin(accessToken, onSuccess)
      } else {
        throw new Error('微信登录未返回 accessToken')
      }
    } finally {
      loginLoading.value = false
    }

    return {
      bindRequired: false,
      result,
      userInfo,
    }
  }

  async function authWechatBind(
    params: {
      account: string
      openid: string
      password: string
    },
    onSuccess?: () => Promise<void> | void,
  ) {
    let userInfo: null | UserInfo = null
    let result: any

    try {
      loginLoading.value = true
      result = await AuthApi.bindWechat(params)

      const accessToken = getAccessToken(result)
      if (accessToken) {
        userInfo = await completeLogin(accessToken, onSuccess)
      } else {
        throw new Error('微信绑定未返回 accessToken')
      }
    } finally {
      loginLoading.value = false
    }

    return {
      result,
      userInfo,
    }
  }

  async function logout(redirect: boolean = true) {
    try {
      await AuthApi.logout()
    } catch {
      // 不做任何处理
    }

    resetAllStores()
    accessStore.setLoginExpired(false)

    // 回登录页带上当前路由地址
    await router.replace({
      path: LOGIN_PATH,
      query: redirect
        ? {
            redirect: encodeURIComponent(router.currentRoute.value.fullPath),
          }
        : {},
    })
  }

  async function fetchUserInfo() {
    // 获取数据字典
    await getDictionaries()

    // 获取基础数据
    await initBasicData()

    // 获取用户信息
    return await updateUserInfo()
  }

  async function updateUserInfo() {
    // 获取用户信息
    const userInfo = await UserApi.getUserInfo()
    userStore.setUserInfo(userInfo)

    // 设置权限码
    const codes = userInfo.permissions || []
    if (userInfo.authorities) {
      userInfo.authorities.forEach((item) => {
        if (item.authority) {
          codes.push(item.authority)
        }
      })
    }
    accessStore.setAccessCodes(codes)

    return userInfo
  }

  function $reset() {
    loginLoading.value = false
  }

  return {
    $reset,
    authLogin,
    authWechatBind,
    authWechatLogin,
    fetchUserInfo,
    updateUserInfo,
    loginLoading,
    logout,
  }
})
