import { AxiosError, isAxiosError, type AxiosResponse, type AxiosInstance, type AxiosRequestConfig } from 'axios'
import { inject, ref } from 'vue'

export interface Response<T> {
  data: T
  message: string
  status: 'Success' | 'Error'
}

export const delay = (delayTime = 100): Promise<void> => {
  return new Promise((resolve) => setTimeout(resolve, delayTime))
}

export interface ErrorData1 {
  error: {
    msg: string | string[]
    status: number
  }
}

export interface RequestOptions {
  url?: string
  param?: string | number
  body?: { [key: string]: unknown }
  query?: string | string[]
  config?: AxiosRequestConfig
}

function generateQuery(data: string | string[]) {
  const q = Array.isArray(data) ? data.join('&') : data
  return '?' + q
}

function getUrl(url?: string, options?: RequestOptions) {
  let reqUrl = url ?? options?.url
  if (!reqUrl) throw new Error('please set url')

  if (options && options.param) reqUrl += '/' + options.param
  if (options && options.query) reqUrl += generateQuery(options.query)

  console.log('URL', reqUrl)
  return reqUrl
}

async function wrap<T>(f: () => Promise<AxiosResponse<T>>) {
  try {
    const { data } = await f()
    return data
  } catch (err) {
    if (isAxiosError(err) && err.response) {
      const statusCode = err.response.status
      const errorObj = err.response.data as Response<null>

      if (errorObj) {
        console.log('ERROR', statusCode, errorObj.message)
      }
    }
    return
  }
}

export function useFetch(url?: string) {
  const error = ref<AxiosError>()
  const axios = inject('axios') as AxiosInstance

  async function GET<T>(options?: RequestOptions) {
    return wrap<Response<T>>(() => axios.get<Response<T>>(getUrl(url, options), options?.config))
  }

  async function POST<T>(options?: RequestOptions) {
    return wrap<Response<T>>(() => axios.post<Response<T>>(getUrl(url, options), options?.body ?? {}, options?.config))
  }

  async function PATCH<T>(options?: RequestOptions) {
    return wrap<Response<T>>(() => axios.patch<Response<T>>(getUrl(url, options), options?.body ?? {}, options?.config))
  }

  async function PUT<T>(options?: RequestOptions) {
    return wrap<Response<T>>(() => axios.put<Response<T>>(getUrl(url, options), options?.body ?? {}, options?.config))
  }

  async function DELETE<T>(options?: RequestOptions) {
    return wrap<Response<T>>(() => axios.delete<Response<T>>(getUrl(url, options), options?.config))
  }

  return { error, GET, POST, PATCH, PUT, DELETE }
}
