import type { AxiosHeaders, AxiosRequestConfig, AxiosResponse } from 'axios'
import axios from 'axios'
import { showToast } from 'vant'
import { userToken, lang, CLIENT } from './config'
import useGlobalStore from '@/stores/use-global-store'
import useUserStore from '@/stores/use-user-store'
import config from '@/config'
const { Host85 } = config

window.axios = axios

interface ResponseData<T = any> {
    code: number
    data: T
    msg: string
}

interface Objable {
    [key: string]: any
}

interface ApiType {
    post: <T = any>(url: string, data?: Objable, header?: Objable, checkCode?: boolean) => Promise<ResponseData<T>>
    get: <T = any>(url: string, data?: Objable, header?: Objable, checkCode?: boolean) => Promise<ResponseData<T>>
    put: <T = any>(url: string, data?: Objable, header?: Objable, checkCode?: boolean) => Promise<ResponseData<T>>
    delete: <T = any>(url: string, data?: Objable, header?: Objable, checkCode?: boolean) => Promise<ResponseData<T>>
    downFile: (url: string, method?: string, data?: Objable) => Promise<AxiosResponse>
    uploadFile: <T = any>(url: string, file: File, data?: Objable, header?: Objable, checkCode?: boolean) => Promise<ResponseData<T>>
    RESTful: <T = any>(url: string, method?: string, data?: Objable, header?: Objable, checkCode?: boolean) => Promise<ResponseData<T>>
    $RESTful: <T = any>(url: string, method?: string, data?: Objable, header?: Objable) => Promise<ResponseData<T>>
}

const headers = {
    'X-Requested-With': 'XMLHttpRequest',
    'Content-Type': 'application/json',
}

const baseConfig = {
    headers,
    timeout: 5000,
    withCredentials: false,
}

if (import.meta.env.VITE_APP_ENV === 'production') {
    baseConfig.timeout = 300000
}

axios.interceptors.request.use(
    config => config,
    error => Promise.resolve(error.response || error),
)

axios.interceptors.response.use(
    response => response,
    (error) => {
        const response = {} as AxiosResponse
        response.config = error.config
        response.data = null
        response.headers = error.config.headers
        response.status = error.code
        response.statusText = error.msg
        response.request = error.request
        return Promise.resolve(response)
    },
)

function checkStatus(response: AxiosResponse): ResponseData<any> {
    if (response.status === 200 || response.status === 304) {
        return response.data
    }
    if (response.status === 401) {
        return {
            code: 401,
            data: response.statusText || response.toString(),
            msg: '您还没有登录, 或者登录超时!',
        }
    }
    return {
        code: -404,
        data: response.statusText || response.toString(),
        msg: `接口返回数据错误`,
    }
}

function checkCodeFn(data: ResponseData<any>) {
    const code = [0, 200, 1000]
    const globalStore = useGlobalStore()
    globalStore.setRequestLoading(false)
    if (data.code === 401 || data.code === 600) {
        userToken.value = ''
        const pathname = encodeURIComponent(window.location.pathname)
        if (!window.$$lock) {
            window.$$lock = true
            loginMsgBox('当前登录状态已失效, 请重新登录', pathname)
        }
    }
    else if (!code.includes(Number(data.code))) {
        showToast(data.msg)
    }
    else {
        data.code = 200
    }
    return data
}

const api: ApiType = {
    post<T = any>(url: string, data?: Objable, header?: Objable, checkCode = true) {
        return this.RESTful<T>(url, 'post', data, header, checkCode)
    },
    get<T = any>(url: string, data?: Objable, header?: Objable, checkCode = true) {
        return this.RESTful<T>(url, 'get', data, header, checkCode)
    },
    put<T = any>(url: string, data?: Objable, header?: Objable, checkCode = true) {
        return this.RESTful<T>(url, 'put', data, header, checkCode)
    },
    delete<T = any>(url: string, data?: Objable, header?: Objable, checkCode = true) {
        return this.RESTful<T>(url, 'delete', data, header, checkCode)
    },
    async downFile(url: string, method = 'get', data?: Objable) {
        const config: AxiosRequestConfig = {
            ...baseConfig,
            responseType: 'arraybuffer',
            method,
            url: Host85 + url,
        }
        if (method === 'get') {
            config.params = data
        }
        else {
            config.data = data
        }

        if (url.includes('NoTimeout')) {
            config.timeout = 9999999
        }
        const response = await axios(config)
        return response
    },
    async uploadFile<T = any>(url: string, file: File, data?: Objable, header?: Objable, checkCode = true) {
        const formData = new FormData()
        formData.append('file', file)

        if (data) {
            Object.keys(data).forEach(key => {
                formData.append(key, data[key])
            })
        }

        const config: AxiosRequestConfig = {
            ...baseConfig,
            headers: {
                ...baseConfig.headers,
                'Content-Type': 'multipart/form-data',
                ...header,
            },
            method: 'post',
            url: Host85 + url,
            data: formData,
        }

        if (userToken.value) {
            (config.headers as AxiosHeaders)['Access-Token'] = `${userToken.value}`
        }
        if (lang.value) {
            (config.headers as AxiosHeaders)['Language'] = `${lang.value}`
        }
        if (CLIENT.value) {
            (config.headers as AxiosHeaders)['CLIENT'] = `${CLIENT.value}`
        }

        if (url.includes('NoTimeout')) {
            config.timeout = 9999999
        }

        const response = await axios(config)
        const result = checkStatus(response)
        if (checkCode) {
            return checkCodeFn(result)
        }
        return result
    },
    async RESTful<T = any>(url: string, method = 'get', data?: Objable, header?: Objable, checkCode = true) {
        const xhr = await this.$RESTful<T>(url, method, data, header)
        if (checkCode) {
            return checkCodeFn(xhr)
        }
        return xhr
    },
    async $RESTful<T = any>(url: string, method = 'get', data?: Objable, header?: Objable) {
        const globalStore = useGlobalStore()
        if (!globalStore.fullScreenLoading && !globalStore.requestLoading) {
            globalStore.setRequestLoading(true)
        }
        url = Host85 + url
        const config: AxiosRequestConfig = {
            ...baseConfig,
            headers: {
                ...baseConfig.headers,
                ...header,
            },
            method,
            url,
        }
        if (userToken.value) {
            (config.headers as AxiosHeaders)['Access-Token'] = `${userToken.value}`
        }
        if (lang.value) {
            (config.headers as AxiosHeaders)['Language'] = `${lang.value}`
        }
        if (CLIENT.value) {
            (config.headers as AxiosHeaders)['CLIENT'] = `${CLIENT.value}`
        }
        const userStore = useUserStore()
        const cId = userStore.userInfo?.customInfo?.cId

        if (method === 'get') {
            config.params = { ...data, cId }
        }
        else {
            config.data = { ...data, cId }
        }

        if (url.includes('NoTimeout')) {
            config.timeout = 9999999
        }
        const response = await axios(config)
        return checkStatus(response)
    },
}

window.$$api = api
export const $api = api
