import type { FetchOptions } from 'ofetch'

export interface ApiOptions extends FetchOptions {
  auth?: boolean
}

// Every HTTP verb supported by $fetch. Typing `method` explicitly
// (instead of letting ofetch infer a wide string) keeps the fetch
// call type-safe across the whole app.
type ApiMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE'

export const useApi = () => {
  const config = useRuntimeConfig()

  const request = async <T = any>(
    url: string,
    options: ApiOptions = {}
  ): Promise<T> => {
    // Determine the base URL: use API_URL if defined, otherwise apiBase.
    // String() guarantees the value is never `undefined` even when all
    // runtime-config keys are unset (empty string is a valid ofetch baseURL).
    const baseURL = String(config.public.NUXT_PUBLIC_API_URL || config.public.API_URL || config.public.apiBase || '')

    // Attempt to read both the XCTN-TOKEN (used in this app) and generic 'token'
    const xctnToken = useCookie<string | null>('XCTN-TOKEN')
    const genericToken = useCookie<string | null>('token')
    const activeToken = xctnToken.value || genericToken.value

    // auth defaults to true. Can be disabled via options.auth = false
    const useAuth = options.auth !== false

    // Forward cookies if running on the server
    const requestHeaders = import.meta.server ? useRequestHeaders(['cookie']) : {}

    const headers: any = {
      Accept: 'application/json',
      ...requestHeaders,
      ...(options.headers || {})
    }

    if (useAuth && activeToken) {
      headers.Authorization = `Bearer ${activeToken}`
    }

    try {
      return await $fetch<T>(url, {
        baseURL,
        ...options,
        // Forward the caller's HTTP verb (defaults to GET) with our narrowed type.
        method: options.method as ApiMethod,
        headers
      })
    } catch (error: any) {
      // Optional: Add Automatic 401 Handling
      if (error.status === 401 && useAuth) {
        xctnToken.value = null
        genericToken.value = null
        await navigateTo('/login')
      }
      throw error
    }
  }

  return {
    get: <T = any>(url: string, query?: Record<string, any>, options?: ApiOptions) =>
      request<T>(url, {
        method: 'GET',
        query,
        ...options
      }),

    post: <T = any>(url: string, body?: any, options?: ApiOptions) =>
      request<T>(url, {
        method: 'POST',
        body,
        ...options
      }),

    put: <T = any>(url: string, body?: any, options?: ApiOptions) =>
      request<T>(url, {
        method: 'PUT',
        body,
        ...options
      }),

    patch: <T = any>(url: string, body?: any, options?: ApiOptions) =>
      request<T>(url, {
        method: 'PATCH',
        body,
        ...options
      }),

    delete: <T = any>(url: string, options?: ApiOptions) =>
      request<T>(url, {
        method: 'DELETE',
        ...options
      })
  }
}
