import axios from 'axios'
import toCamel from 'camelcase-keys'

import { API_BASE_URL } from '@/config'

import type { AxiosError, AxiosRequestConfig } from 'axios'

type Opt = {
    params?:        AxiosRequestConfig['params']
    headers?:       Record<string, string>
    signal?:        AbortSignal
    responseType?:  'blob' }

const client = axios.create ({ baseURL: API_BASE_URL })


const withUserCode = (opt?: Opt): Opt => ({
    ...opt,
    headers: { 'X-Transfer-Code': localStorage.getItem ('user_code') ?? '',
	       ...(opt?.headers ?? { }) } })


const apiP = async <T> (
    method: 'post' | 'put' | 'patch',
    path:   string,
    body?:  unknown,
    opt?:   Opt): Promise<T> => {
  const res = await client[method] (path, body ?? { }, withUserCode (opt))
  if (opt?.responseType === 'blob')
    return res.data as T
  return toCamel (res.data as Record<string, unknown>, { deep: true }) as T
}


export const apiGet = async <T> (
    path: string,
    opt?: Opt): Promise<T> => {
  const res = await client.get (path, withUserCode (opt))
  if (opt?.responseType === 'blob')
    return res.data as T
  return toCamel (res.data as Record<string, unknown>, { deep: true }) as T
}


export const apiPost = async <T> (
    path:   string,
    body?:  unknown,
    opt?:   Opt): Promise<T> => apiP ('post', path, body, opt)


export const apiPut = async <T> (
    path:   string,
    body?:  unknown,
    opt?:   Opt): Promise<T> => apiP ('put', path, body, opt)


export const apiPatch = async <T> (
    path:   string,
    body?:  unknown,
    opt?:   Opt): Promise<T> => apiP ('patch', path, body, opt)


export const apiDelete = async <T = void> (
    path: string,
    opt?: Opt): Promise<T> => {
  const res = await client.delete (path, withUserCode (opt))
  if (res.data == null || res.data === '')
    return undefined as T
  return toCamel (res.data as Record<string, unknown>, { deep: true }) as T
}


export const isApiError = <T = unknown> (err: unknown): err is AxiosError<T> =>
    axios.isAxiosError (err)
