import { ElNotification } from 'element-plus'
import { isArray } from 'lodash-es'
import { state } from './store'
import { moduleInstallState, type moduleState } from './types'
import {
    changeState,
    createOrder,
    getInstallState,
    index,
    info,
    modules,
    payCheck,
    payOrder,
    postInstallModule,
    preDownload,
} from '/@/api/backend/module'
import { i18n } from '/@/lang/index'
import router from '/@/router/index'
import { useBaAccount } from '/@/stores/baAccount'
import { SYSTEM_ZINDEX } from '/@/stores/constant/common'
import { taskStatus } from '/@/stores/constant/terminalTaskStatus'
import type { UserInfo } from '/@/stores/interface'
import { useTerminal } from '/@/stores/terminal'
import { fullUrl } from '/@/utils/common'
import { uuid } from '/@/utils/random'
import { changeListenDirtyFileSwitch, closeHotUpdate } from '/@/utils/vite'

export const loadData = () => {
    state.loading.table = true
    if (!state.table.indexLoaded) {
        loadIndex().then(() => {
            getModules()
        })
    } else {
        getModules()
    }
}

export const onRefreshTableData = () => {
    state.table.indexLoaded = false
    for (const key in state.table.modulesEbak) {
        state.table.modulesEbak[key] = undefined
    }
    loadData()
}

const loadIndex = () => {
    return index().then((res) => {
        state.table.indexLoaded = true
        state.sysVersion = res.data.sysVersion
        state.nuxtVersion = res.data.nuxtVersion
        state.installedModule = res.data.installed

        const installedModuleUids: string[] = []
        const installedModuleVersions: { uid: string; version: string }[] = []
        if (res.data.installed) {
            state.installedModule.forEach((item) => {
                installedModuleUids.push(item.uid)
                installedModuleVersions.push({
                    uid: item.uid,
                    version: item.version,
                })
            })
            state.installedModuleUids = installedModuleUids
            state.installedModuleVersions = installedModuleVersions
        }
    })
}

const getModules = () => {
    if (typeof state.table.modulesEbak[state.table.params.activeTab] != 'undefined') {
        state.table.modules[state.table.params.activeTab] = modulesOnlyLocalHandle(state.table.modulesEbak[state.table.params.activeTab])
        state.loading.table = false
        return
    }
    const params: anyObj = {}
    for (const key in state.table.params) {
        if (state.table.params[key] != '') {
            params[key] = state.table.params[key]
        }
    }
    const moduleUids: string[] = []
    params['installed'] = state.installedModuleVersions
    params['sysVersion'] = state.sysVersion
    modules(params)
        .then((res) => {
            if (params.activeTab == 'all') {
                res.data.rows.forEach((item: anyObj) => {
                    moduleUids.push(item.uid)
                })

                state.installedModule.forEach((item) => {
                    if (moduleUids.indexOf(item.uid) === -1) {
                        if (state.table.params.quickSearch) {
                            if (item.title.includes(state.table.params.quickSearch)) res.data.rows.push(item)
                        } else {
                            res.data.rows.push(item)
                        }
                    }
                })
            }

            state.table.remark = res.data.remark
            state.table.modulesEbak[params.activeTab] = res.data.rows.map((item: anyObj) => {
                const idx = state.installedModuleUids.indexOf(item.uid)
                if (idx !== -1) {
                    item.state = state.installedModule[idx].state
                    item.title = state.installedModule[idx].title
                    item.version = state.installedModule[idx].version
                    item.website = state.installedModule[idx].website
                    item.stateTag = moduleStatus(item.state)

                    if (!isArray(item.tags)) item.tags = []
                    item.tags.push({
                        name: `${i18n.global.t('module.installed')} v${state.installedModule[idx].version}`,
                        type: 'primary',
                    })
                } else {
                    item.state = 0
                }

                if (item.new_version && item.tags) {
                    item.tags.push({
                        name: i18n.global.t('module.New version'),
                        type: 'danger',
                    })
                }

                return item
            })
            state.table.modules[params.activeTab] = modulesOnlyLocalHandle(state.table.modulesEbak[params.activeTab])
            state.table.category = res.data.category
        })
        .finally(() => {
            state.loading.table = false
        })
}

export const showInfo = (uid: string) => {
    state.dialog.goodsInfo = true
    state.loading.goodsInfo = true

    const localItem = state.installedModule.find((item) => {
        return item.uid == uid
    })

    info({
        uid: uid,
        localVersion: localItem?.version,
        sysVersion: state.sysVersion,
    })
        .then((res) => {
            if (localItem) {
                if (res.data.info.type == 'local') {
                    res.data.info = localItem
                    res.data.info.images = [fullUrl('/static/images/local-module-logo.png')]
                    res.data.info.type = 'local' // 纯本地模块
                } else {
                    res.data.info.type = 'online'
                    res.data.info.state = localItem.state
                    res.data.info.version = localItem.version
                }
                res.data.info.enable = localItem.state === moduleInstallState.DISABLE ? false : true
            } else {
                res.data.info.state = 0
                res.data.info.type = 'online'
            }
            state.goodsInfo = res.data.info
        })
        .catch((err) => {
            if (loginExpired(err)) {
                state.dialog.goodsInfo = false
            }
        })
        .finally(() => {
            state.loading.goodsInfo = false
        })
}

/**
 * 支付订单
 * @param renew 是否是续费订单
 */
export const onBuy = (renew = false) => {
    state.dialog.buy = true
    state.loading.buy = true
    createOrder({
        goods_id: state.goodsInfo.id,
    })
        .then((res) => {
            state.loading.buy = false
            state.buy.renew = renew
            state.buy.info = res.data.info
        })
        .catch((err) => {
            state.dialog.buy = false
            state.loading.buy = false
            loginExpired(err)
        })
}

export const onPay = (payType: 'score' | 'wx' | 'balance' | 'zfb') => {
    state.common.payType = payType
    state.loading.common = true
    payOrder(state.buy.info.id, payType)
        .then((res) => {
            // 关闭其他弹窗
            state.dialog.buy = false
            state.dialog.goodsInfo = false

            if (payType == 'wx' || payType == 'zfb') {
                // 显示支付二维码
                state.dialog.pay = true
                state.payInfo = res.data

                // 轮询获取支付状态
                const timer = setInterval(() => {
                    payCheck(state.payInfo.info.sn)
                        .then(() => {
                            state.payInfo.pay.status = 'success'
                            clearInterval(timer)
                            if (state.buy.renew) {
                                showInfo(res.data.info.uid)
                            } else {
                                onPreInstallModule(res.data.info.uid, res.data.info.id, true)
                            }
                            state.dialog.pay = false
                        })
                        .catch(() => {})
                }, 3000)
            } else {
                if (state.buy.renew) {
                    showInfo(res.data.info.uid)
                } else {
                    onPreInstallModule(res.data.info.uid, res.data.info.id, true)
                }
            }
        })
        .catch((err) => {
            loginExpired(err)
        })
        .finally(() => {
            state.loading.common = false
        })
}

export const showCommonLoading = (loadingTitle: moduleState['common']['loadingTitle']) => {
    state.common.type = 'loading'
    state.common.loadingTitle = loadingTitle
    state.common.loadingComponentKey = uuid()
}

/**
 * 模块预安装
 */
export const onPreInstallModule = (uid: string, id: number, needGetInstallableVersion: boolean, update: boolean = false) => {
    state.dialog.common = true
    showCommonLoading('init')
    state.common.dialogTitle = i18n.global.t('module.Install')

    const nextStep = (moduleState: number) => {
        if (needGetInstallableVersion) {
            // 获取模块版本列表
            showCommonLoading('getInstallableVersion')
            preDownload({
                uid,
                orderId: id,
                sysVersion: state.sysVersion,
                nuxtVersion: state.nuxtVersion,
                installed: state.installedModuleUids,
            })
                .then((res) => {
                    state.common.uid = uid
                    state.common.update = update
                    state.common.type = 'selectVersion'
                    state.common.dialogTitle = i18n.global.t('module.Select Version')
                    state.common.versions = res.data.versions

                    // 关闭其他弹窗
                    state.dialog.baAccount = false
                    state.dialog.buy = false
                    state.dialog.goodsInfo = false
                })
                .catch((res) => {
                    if (loginExpired(res)) return
                    state.dialog.common = false
                })
        } else {
            // 立即安装（上传安装、继续安装）
            showCommonLoading(moduleState === moduleInstallState.UNINSTALLED ? 'download' : 'install')
            execInstall(uid, id, '', update)

            // 关闭其他弹窗
            state.dialog.baAccount = false
            state.dialog.buy = false
            state.dialog.goodsInfo = false
        }
    }

    if (update) {
        nextStep(moduleInstallState.DISABLE)
    } else {
        // 获取安装状态
        getInstallState(uid).then((res) => {
            if (
                res.data.state === moduleInstallState.INSTALLED ||
                res.data.state === moduleInstallState.DISABLE ||
                res.data.state === moduleInstallState.DIRECTORY_OCCUPIED
            ) {
                ElNotification({
                    type: 'error',
                    message:
                        res.data.state === moduleInstallState.INSTALLED || res.data.state === moduleInstallState.DISABLE
                            ? i18n.global.t('module.Installation cancelled because module already exists!')
                            : i18n.global.t('module.Installation cancelled because the directory required by the module is occupied!'),
                })
                state.dialog.common = false
                return
            }

            nextStep(res.data.state)
        })
    }
}

/**
 * 执行安装请求，还包含启用、安装时的冲突处理
 */
export const execInstall = (uid: string, id: number, version: string = '', update: boolean = false, extend: anyObj = {}) => {
    postInstallModule(uid, id, version, update, extend)
        .then(() => {
            state.common.dialogTitle = i18n.global.t('module.Installation complete')
            state.common.moduleState = moduleInstallState.INSTALLED
            state.common.type = 'done'
            onRefreshTableData()
        })
        .catch((res) => {
            if (loginExpired(res)) return
            if (res.code == -1) {
                state.common.uid = res.data.uid
                state.common.type = 'installConflict'
                state.common.dialogTitle = i18n.global.t('module.A conflict is found Please handle it manually')
                state.common.fileConflict = res.data.fileConflict
                state.common.dependConflict = res.data.dependConflict
            } else if (res.code == -2) {
                state.common.type = 'done'
                state.common.uid = res.data.uid
                state.common.dialogTitle = i18n.global.t('module.Wait for dependent installation')
                state.common.moduleState = moduleInstallState.DEPENDENT_WAIT_INSTALL
                state.common.waitInstallDepend = res.data.wait_install
                state.common.dependInstallState = 'executing'
                const terminal = useTerminal()
                if (res.data.wait_install.includes('npm_dependent_wait_install')) {
                    terminal.addTaskPM('web-install', true, 'module-install:' + res.data.uid, (res: number) => {
                        terminalTaskExecComplete(res, 'npm_dependent_wait_install')
                    })
                }
                if (res.data.wait_install.includes('nuxt_npm_dependent_wait_install')) {
                    terminal.addTaskPM('nuxt-install', true, 'module-install:' + res.data.uid, (res: number) => {
                        terminalTaskExecComplete(res, 'nuxt_npm_dependent_wait_install')
                    })
                }
                if (res.data.wait_install.includes('composer_dependent_wait_install')) {
                    terminal.addTask('composer.update', true, 'module-install:' + res.data.uid, (res: number) => {
                        terminalTaskExecComplete(res, 'composer_dependent_wait_install')
                    })
                }
            } else if (res.code == 0) {
                ElNotification({
                    type: 'error',
                    message: res.msg,
                    zIndex: SYSTEM_ZINDEX,
                })
                state.dialog.common = false
                onRefreshTableData()
            }
        })
        .finally(() => {
            state.loading.common = false
        })
}

const terminalTaskExecComplete = (res: number, type: string) => {
    if (res == taskStatus.Success) {
        state.common.waitInstallDepend = state.common.waitInstallDepend.filter((depend: string) => {
            return depend != type
        })
        if (state.common.waitInstallDepend.length == 0) {
            state.common.dependInstallState = 'success'

            // 仅在命令全部执行完毕才刷新数据
            if (router.currentRoute.value.name === 'moduleStore/moduleStore') {
                onRefreshTableData()
            }
        }
    } else {
        const terminal = useTerminal()
        terminal.toggle(true)
        state.common.dependInstallState = 'fail'

        // 有命令执行失败了，刷新一次数据
        if (router.currentRoute.value.name === 'moduleStore/moduleStore') {
            onRefreshTableData()
        }
    }

    // 连续安装模块的情况中，首个模块的命令执行完毕时，自动启动了热更新
    if (router.currentRoute.value.name === 'moduleStore/moduleStore') {
        closeHotUpdate('modules')
    }
}

export const onDisable = (confirmConflict = false) => {
    state.loading.common = true

    // 拼装依赖处理方案
    if (confirmConflict) {
        const dependConflict: anyObj = {}
        for (const key in state.common.disableDependConflict) {
            if (state.common.disableDependConflict[key]['solution'] != 'delete') {
                continue
            }
            if (typeof dependConflict[state.common.disableDependConflict[key].env] == 'undefined') {
                dependConflict[state.common.disableDependConflict[key].env] = []
            }
            dependConflict[state.common.disableDependConflict[key].env].push(state.common.disableDependConflict[key].depend)
        }
        state.common.disableParams['confirmConflict'] = 1
        state.common.disableParams['dependConflictSolution'] = dependConflict
    }

    changeState(state.common.disableParams)
        .then(() => {
            ElNotification({
                type: 'success',
                message: i18n.global.t('module.The operation succeeds Please clear the system cache and refresh the browser ~'),
                zIndex: SYSTEM_ZINDEX,
            })
            state.dialog.common = false
            onRefreshTableData()
        })
        .catch((res) => {
            if (res.code == -1) {
                state.dialog.common = true
                state.common.dialogTitle = i18n.global.t('module.Deal with conflict')
                state.common.type = 'disableConfirmConflict'
                state.common.disableDependConflict = res.data.dependConflict
                if (res.data.conflictFile && res.data.conflictFile.length) {
                    const conflictFile = []
                    for (const key in res.data.conflictFile) {
                        conflictFile.push({
                            file: res.data.conflictFile[key],
                        })
                    }
                    state.common.disableConflictFile = conflictFile
                }
            } else if (res.code == -2) {
                state.dialog.common = true
                const commandsData = {
                    type: 'disable',
                    commands: res.data.wait_install,
                }
                state.common.uid = state.goodsInfo.uid
                execCommand(commandsData)
            } else if (res.code == -3) {
                // 更新
                onPreInstallModule(state.goodsInfo.uid, state.goodsInfo.purchased, true, true)
            } else {
                ElNotification({
                    type: 'error',
                    message: res.msg,
                    zIndex: SYSTEM_ZINDEX,
                })
                if (state.common.disableParams && state.common.disableParams.uid) {
                    showInfo(state.common.disableParams.uid)
                } else {
                    onRefreshTableData()
                }
            }
        })
        .finally(() => {
            state.loading.common = false
        })
}

export const onEnable = (uid: string) => {
    state.loading.common = true
    changeState({
        uid: uid,
        state: 1,
    })
        .then(() => {
            state.dialog.common = true
            showCommonLoading('init')
            state.common.dialogTitle = i18n.global.t('Enable')

            execInstall(uid, 0)
            state.dialog.goodsInfo = false
        })
        .catch((res) => {
            ElNotification({
                type: 'error',
                message: res.msg,
                zIndex: SYSTEM_ZINDEX,
            })
            state.loading.common = false
        })
}

export const loginExpired = (res: ApiResponse) => {
    const baAccount = useBaAccount()
    if (res.code == 301 || res.code == 408) {
        baAccount.removeToken()
        state.dialog.baAccount = true
        return true
    }
    return false
}

const modulesOnlyLocalHandle = (modules: anyObj) => {
    if (!state.table.onlyLocal) return modules
    return modules.filter((item: anyObj) => {
        return item.installed
    })
}

export const execCommand = (data: anyObj) => {
    if (data.type == 'disable') {
        state.dialog.common = true
        state.common.type = 'done'
        state.common.dialogTitle = i18n.global.t('module.Wait for dependent installation')
        state.common.moduleState = moduleInstallState.DISABLE
        state.common.dependInstallState = 'executing'
        const terminal = useTerminal()
        data.commands.forEach((item: anyObj) => {
            state.common.waitInstallDepend.push(item.type)
            if (item.pm) {
                if (item.command == 'web-install') {
                    changeListenDirtyFileSwitch(false)
                }
                terminal.addTaskPM(item.command, true, '', (res: number) => {
                    terminalTaskExecComplete(res, item.type)
                    if (item.command == 'web-install') {
                        changeListenDirtyFileSwitch(true)
                    }
                })
            } else {
                terminal.addTask(item.command, true, '', (res: number) => {
                    terminalTaskExecComplete(res, item.type)
                })
            }
        })
    }
}

export const specificUserName = (userInfo: Partial<UserInfo>) => {
    return userInfo.nickname + '（' + (userInfo.email || userInfo.mobile || 'ID:' + userInfo.id) + '）'
}

export const currency = (price: number, val: number) => {
    if (typeof price == 'undefined' || typeof val == 'undefined') {
        return '-'
    }
    if (val == 0) {
        return parseInt(price.toString()) + i18n.global.t('Integral')
    } else {
        return '￥' + price
    }
}

export const moduleStatus = (state: number) => {
    switch (state) {
        case moduleInstallState.INSTALLED:
            return {
                type: '',
                text: i18n.global.t('module.installed'),
            }
        case moduleInstallState.WAIT_INSTALL:
            return {
                type: 'success',
                text: i18n.global.t('module.Wait for installation'),
            }
        case moduleInstallState.CONFLICT_PENDING:
            return {
                type: 'danger',
                text: i18n.global.t('module.Conflict pending'),
            }
        case moduleInstallState.DEPENDENT_WAIT_INSTALL:
            return {
                type: 'warning',
                text: i18n.global.t('module.Dependency to be installed'),
            }
        case moduleInstallState.DISABLE:
            return {
                type: 'warning',
                text: i18n.global.t('Disable'),
            }
        default:
            return {
                type: 'info',
                text: i18n.global.t('Unknown'),
            }
    }
}
