/**
 * Base API composable for making HTTP requests to the tideway backend.
 * Handles authentication headers and token refresh automatically.
 */

const API_BASE_URL = import.meta.env.VITE_API_URL || '{{api_base_url}}'

interface RequestOptions extends Omit<RequestInit, 'body'> {
  body?: unknown
}

class ApiError extends Error {
  status: number
  data?: unknown

  constructor(message: string, status: number, data?: unknown) {
    super(message)
    this.name = 'ApiError'
    this.status = status
    this.data = data
  }
}

export function useApi() {
  function getAuthHeaders(): Record<string, string> {
    const token = localStorage.getItem('access_token')
    if (token) {
      return { Authorization: `Bearer ${token}` }
    }
    return {}
  }

  async function request<T>(endpoint: string, options: RequestOptions = {}): Promise<T> {
    const url = `${API_BASE_URL}${endpoint}`
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
      ...getAuthHeaders(),
      ...(options.headers as Record<string, string> || {}),
    }

    const config: RequestInit = {
      ...options,
      headers,
      body: options.body ? JSON.stringify(options.body) : undefined,
    }

    const response = await fetch(url, config)

    // Handle 401 - try to refresh token
    if (response.status === 401) {
      const refreshed = await tryRefreshToken()
      if (refreshed) {
        // Retry the original request with new token
        const retryHeaders = {
          ...headers,
          ...getAuthHeaders(),
        }
        const retryResponse = await fetch(url, { ...config, headers: retryHeaders })
        if (!retryResponse.ok) {
          throw new ApiError(
            'Request failed after token refresh',
            retryResponse.status,
            await retryResponse.json().catch(() => null)
          )
        }
        return retryResponse.json()
      }

      // Refresh failed, clear tokens and redirect to login
      localStorage.removeItem('access_token')
      localStorage.removeItem('refresh_token')
      window.location.href = '/login'
      throw new ApiError('Session expired', 401)
    }

    if (!response.ok) {
      const data = await response.json().catch(() => null)
      const message = data?.message || data?.error || `Request failed with status ${response.status}`
      throw new ApiError(message, response.status, data)
    }

    // Handle empty responses
    const text = await response.text()
    if (!text) {
      return {} as T
    }

    return JSON.parse(text)
  }

  async function tryRefreshToken(): Promise<boolean> {
    const refreshToken = localStorage.getItem('refresh_token')
    if (!refreshToken) {
      return false
    }

    try {
      const response = await fetch(`${API_BASE_URL}/auth/refresh`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ refresh_token: refreshToken }),
      })

      if (!response.ok) {
        return false
      }

      const data = await response.json()
      if (data.access_token && data.refresh_token) {
        localStorage.setItem('access_token', data.access_token)
        localStorage.setItem('refresh_token', data.refresh_token)
        return true
      }

      return false
    } catch {
      return false
    }
  }

  return {
    get: <T>(endpoint: string, options?: RequestOptions) =>
      request<T>(endpoint, { ...options, method: 'GET' }),

    post: <T>(endpoint: string, body?: unknown, options?: RequestOptions) =>
      request<T>(endpoint, { ...options, method: 'POST', body }),

    put: <T>(endpoint: string, body?: unknown, options?: RequestOptions) =>
      request<T>(endpoint, { ...options, method: 'PUT', body }),

    patch: <T>(endpoint: string, body?: unknown, options?: RequestOptions) =>
      request<T>(endpoint, { ...options, method: 'PATCH', body }),

    delete: <T>(endpoint: string, options?: RequestOptions) =>
      request<T>(endpoint, { ...options, method: 'DELETE' }),
  }
}

export { ApiError }
