import axios, { AxiosResponse } from 'axios'
import React, { createContext, useContext } from 'react'

type Props = {
  children: React.ReactNode
  baseURL?: string
}

type AppContextInterface = {
  get: <T>(path: string) => Promise<T>
  patch: <T>(path: string, body: Partial<T>) => Promise<T>
  post: <T, R = T>(path: string, body: Partial<T>) => Promise<R>
  create: <T>(path: string, body: Partial<T>) => Promise<T>
  destroy: (path: string) => Promise<string>
  baseURL?: string
}

const AppContext = createContext<AppContextInterface | null>(null)

export const AppContextProvider = ({ children, baseURL }: Props) => {
  const api = axios.create({ baseURL })

  api.interceptors.request.use((config) => {
    // config.url += '?format=json'
    config.headers = {
      Authorization: `Token ${window.localStorage.getItem(
        'cash-stacks-token',
      )}`,
    }
    return config
  })

  async function get<T>(path: string): Promise<T> {
    const res = await api.get<T>(path)
    return res.data
  }
  async function patch<T>(path: string, body: Partial<T>) {
    const res = await api.patch<T>(path, body)
    return res.data
  }
  async function post<T, R = T>(path: string, body: Partial<T>) {
    const res = await api.post<T, AxiosResponse<R>>(path, body)
    return res.data
  }
  async function create<T>(path: string, body: Partial<T>) {
    // unauthed POST
    const res = await api.post<T>(path, body)
    return res.data
  }
  async function destroy(path: string) {
    const res = await api.delete<string>(path)
    return res.data
  }

  return (
    <AppContext.Provider value={{ get, patch, post, create, destroy, baseURL }}>
      {children}
    </AppContext.Provider>
  )
}

export const useAppContext = () => {
  const context = useContext(AppContext)

  if (!context)
    throw new Error(
      'AppContext must be called from within the AppContextProvider',
    )

  return context
}
