import { apiUrl } from '../lib/apiOrigin'

const TOKEN_KEY = 'alrahma_api_token'

export function getStoredToken(): string | null {
  return localStorage.getItem(TOKEN_KEY)
}

export function setStoredToken(token: string | null): void {
  if (token) localStorage.setItem(TOKEN_KEY, token)
  else localStorage.removeItem(TOKEN_KEY)
}

export function decodeJwtPayload<T = unknown>(token: string): T | null {
  try {
    const payload = token.split('.')[1]
    if (!payload) return null

    const base64 = payload.replace(/-/g, '+').replace(/_/g, '/')
    const json = decodeURIComponent(
      atob(base64)
        .split('')
        .map((char) => `%${char.charCodeAt(0).toString(16).padStart(2, '0')}`)
        .join(''),
    )

    return JSON.parse(json) as T
  } catch {
    return null
  }
}

export class ApiHttpError extends Error {
  readonly status: number
  readonly body: unknown

  constructor(message: string, status: number, body: unknown) {
    super(message)
    this.name = 'ApiHttpError'
    this.status = status
    this.body = body
  }
}

export async function apiFetch<T>(
  path: string,
  init: RequestInit = {},
  opts: { attachAuth?: boolean } = {},
): Promise<T> {
  const attachAuth = opts.attachAuth !== false
  const headers = new Headers(init.headers)

  if (!headers.has('Accept')) {
    headers.set('Accept', 'application/json')
  }

  const token = getStoredToken()

  if (attachAuth && token && !headers.has('Authorization')) {
    headers.set('Authorization', `Bearer ${token}`)
  }

  const url = apiUrl(path)

  let res: Response

  try {
    res = await fetch(url, {
      ...init,
      headers,
    })
  } catch (e) {
    const hint = import.meta.env.DEV
      ? ' Start the API and ensure Vite can reach it. Default proxy is http://localhost:8000 unless VITE_PROXY_API or VITE_API_ORIGIN is set.'
      : ''

    const reason = e instanceof Error ? e.message : 'Failed to fetch'

    throw new ApiHttpError(`Network error: ${reason}.${hint}`, 0, null)
  }

  const body: unknown = await res.json().catch(() => null)

  if (!res.ok) {
    const msg =
      typeof body === 'object' && body !== null && 'message' in body
        ? String((body as { message?: unknown }).message ?? '')
        : ''

    throw new ApiHttpError(msg || `HTTP ${res.status}`, res.status, body)
  }

  return body as T
}
