import type { UserInfo } from '/#/store'
import type { ErrorMessageMode } from '/#/axios'
import { defineStore } from 'pinia'
import { store } from '/@/store'
import type { RoleEnum } from '/@/enums/roleEnum'
import { PageEnum } from '/@/enums/pageEnum'
import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum'
import { getAuthCache, setAuthCache } from '/@/utils/auth'
import type { GetUserInfoModel, LoginParams } from '/@/api/sys/model/userModel'
import { doLogout, getUserInfo, loginApi } from '/@/api/sys/user'
import { useI18n } from '/@/hooks/web/useI18n'
import { useMessage } from '/@/hooks/web/useMessage'
import { router } from '/@/router'
import { usePermissionStore } from '/@/store/modules/permission'
import type { RouteRecordRaw } from 'vue-router'
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'
import { isArray } from '/@/utils/is'
import { h } from 'vue'

interface UserState {
    userInfo: Nullable<UserInfo>
    token?: string
    roleList: RoleEnum[]
    sessionTimeout?: boolean
    lastUpdateTime: number
}

export const useUserStore = defineStore({
    id: 'app-user',
    state: (): UserState => ({
        // user info
        userInfo: null,
        // token
        token: undefined,
        // roleList
        roleList: [],
        // Whether the login expired
        sessionTimeout: false,
        // Last fetch time
        lastUpdateTime: 0,
    }),
    getters: {
        getUserInfo(): UserInfo {
            return this.userInfo || getAuthCache<UserInfo>(USER_INFO_KEY) || ({} as UserInfo)
        },
        getToken(): string {
            return this.token || getAuthCache<string>(TOKEN_KEY)
        },
        getRoleList(): RoleEnum[] {
            return this.roleList.length > 0 ? this.roleList : getAuthCache<RoleEnum[]>(ROLES_KEY)
        },
        getSessionTimeout(): boolean {
            return !!this.sessionTimeout
        },
        getLastUpdateTime(): number {
            return this.lastUpdateTime
        },
    },
    actions: {
        setToken(info: string | undefined) {
            this.token = info || '' // for null or undefined value
            setAuthCache(TOKEN_KEY, info)
        },
        setRoleList(roleList: RoleEnum[]) {
            this.roleList = roleList
            setAuthCache(ROLES_KEY, roleList)
        },
        setUserInfo(info: UserInfo | null) {
            this.userInfo = info
            this.lastUpdateTime = new Date().getTime()
            setAuthCache(USER_INFO_KEY, info)
        },
        setSessionTimeout(flag: boolean) {
            this.sessionTimeout = flag
        },
        resetState() {
            this.userInfo = null
            this.token = ''
            this.roleList = []
            this.sessionTimeout = false
        },
        /**
         * @description: login
         */
        async login(
            params: LoginParams & {
                goHome?: boolean
                mode?: ErrorMessageMode
            },
        ): Promise<GetUserInfoModel | null> {
            try {
                const { goHome = true, mode, ...loginParams } = params
                const data = await loginApi(loginParams, mode)
                const { token } = data

                // save token
                this.setToken(token)
                return this.afterLoginAction(goHome)
            } catch (error) {
                return Promise.reject(error)
            }
        },
        async afterLoginAction(goHome?: boolean): Promise<GetUserInfoModel | null> {
            if (!this.getToken) return null
            // get user info
            const userInfo = await this.getUserInfoAction()

            const sessionTimeout = this.sessionTimeout
            if (sessionTimeout) {
                this.setSessionTimeout(false)
            } else {
                const permissionStore = usePermissionStore()
                if (!permissionStore.isDynamicAddedRoute) {
                    const routes = await permissionStore.buildRoutesAction()
                    routes.forEach((route) => {
                        router.addRoute(route as unknown as RouteRecordRaw)
                    })
                    router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw)
                    permissionStore.setDynamicAddedRoute(true)
                }
                goHome && (await router.replace(userInfo?.homePath || PageEnum.BASE_HOME))
            }
            return userInfo
        },
        async getUserInfoAction(): Promise<UserInfo | null> {
            if (!this.getToken) return null
            const userInfo = await getUserInfo()
            const { roles = [] } = userInfo
            if (isArray(roles)) {
                const roleList = roles.map((item) => item.uid) as RoleEnum[]
                this.setRoleList(roleList)
            } else {
                userInfo.roles = []
                this.setRoleList([])
            }
            this.setUserInfo(userInfo)
            return userInfo
        },
        /**
         * @description: logout
         */
        async logout(goLogin = false) {
            if (this.getToken) {
                try {
                    await doLogout()
                } catch {
                    console.log('注销Token失败')
                }
            }
            this.setToken(undefined)
            this.setSessionTimeout(false)
            this.setUserInfo(null)
            goLogin && router.push(PageEnum.BASE_LOGIN)
        },

        /**
         * @description: Confirm before logging out
         */
        confirmLoginOut() {
            const { createConfirm } = useMessage()
            const { t } = useI18n()
            createConfirm({
                iconType: 'warning',
                title: () => h('span', t('sys.app.logoutTip')),
                content: () => h('span', t('sys.app.logoutMessage')),
                onOk: async () => {
                    await this.logout(true)
                },
            })
        },
    },
})

// Need to be used outside the setup
export function useUserStoreWithOut() {
    return useUserStore(store)
}
