import type { AxiosProgressEvent, AxiosResponse, GenericAbortSignal } from 'axios'
import request from './axios'

export interface HttpOption {
    url: string
    data?: any
    method?: string
    headers?: any
    onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void
    signal?: GenericAbortSignal
    beforeRequest?: () => void
    afterRequest?: () => void
}

export interface Response<T = any> {
    data: T
    message: string | null
    status: string
}

function http<T = any>({
    url,
    data,
    method,
    headers,
    onDownloadProgress,
    signal,
    beforeRequest,
    afterRequest
}: HttpOption) {
    const successHandler = (res: AxiosResponse<T>) => {
        return res.data
    }

    const failHandler = (error: any) => {
        afterRequest?.()
        throw new Error(error?.message || 'Error')
    }

    beforeRequest?.()

    method = method || 'GET'

    const params = Object.assign(typeof data === 'function' ? data() : data ?? {}, {})

    return method === 'GET'
        ? request.get(url, { params, signal, onDownloadProgress }).then(successHandler, failHandler)
        : request
              .request({ headers, signal, onDownloadProgress, url, method, data: params })
              .then(successHandler, failHandler)
}

export function get<T = any>({
    url,
    data,
    method = 'GET',
    onDownloadProgress,
    signal,
    beforeRequest,
    afterRequest
}: HttpOption): Promise<T> {
    return http<T>({
        url,
        method,
        data,
        onDownloadProgress,
        signal,
        beforeRequest,
        afterRequest
    })
}

export function post<T = any>({
    url,
    data,
    method = 'POST',
    headers,
    onDownloadProgress,
    signal,
    beforeRequest,
    afterRequest
}: HttpOption): Promise<T> {
    return http<T>({
        url,
        method,
        data,
        headers,
        onDownloadProgress,
        signal,
        beforeRequest,
        afterRequest
    })
}

export function put<T = any>({
    url,
    data,
    method = 'PUT',
    headers,
    onDownloadProgress,
    signal,
    beforeRequest,
    afterRequest
}: HttpOption): Promise<T> {
    return http<T>({
        url,
        method,
        data,
        headers,
        onDownloadProgress,
        signal,
        beforeRequest,
        afterRequest
    })
}

export function del<T = any>({
    url,
    data,
    method = 'delete',
    headers,
    onDownloadProgress,
    signal,
    beforeRequest,
    afterRequest
}: HttpOption): Promise<T> {
    return http<T>({
        url,
        method,
        data,
        headers,
        onDownloadProgress,
        signal,
        beforeRequest,
        afterRequest
    })
}

export function patch<T = any>({
    url,
    data,
    method = 'PATCH',
    headers,
    onDownloadProgress,
    signal,
    beforeRequest,
    afterRequest
}: HttpOption): Promise<T> {
    return http<T>({
        url,
        method,
        data,
        headers,
        onDownloadProgress,
        signal,
        beforeRequest,
        afterRequest
    })
}
export default post
