// ---------------------------------------------------------------------------
// Base API client for honeyDue web app
// ---------------------------------------------------------------------------
// All client-side requests go through Next.js API route handlers (proxy).
// The proxy reads the httpOnly `honeydue-token` cookie and forwards it to the
// Go API as an Authorization header. This avoids exposing the token to JS.
// ---------------------------------------------------------------------------

const API_BASE_URL =
  process.env.NEXT_PUBLIC_API_URL || 'https://honeyDue.treytartt.com/api';

/**
 * Server-only base URL. Falls back to the public one so that server
 * components / route handlers can reach the Go API directly.
 */
const SERVER_API_URL = process.env.API_URL || API_BASE_URL;

// ---------------------------------------------------------------------------
// Error class
// ---------------------------------------------------------------------------

export class ApiError extends Error {
  constructor(
    public status: number,
    message: string,
    public details?: Record<string, string[]>,
  ) {
    super(message);
    this.name = 'ApiError';
  }
}

// ---------------------------------------------------------------------------
// Client-side fetcher  (calls Next.js /api/proxy/... routes)
// ---------------------------------------------------------------------------

/**
 * Client-side authenticated fetch. Calls the Next.js catch-all proxy which
 * attaches the auth token from the httpOnly cookie before forwarding to Go.
 *
 * @param path  API path *without* the `/api` prefix, e.g. `/tasks/`
 * @param options  Standard RequestInit overrides
 */
export async function apiFetch<T>(
  path: string,
  options: RequestInit = {},
): Promise<T> {
  // Strip trailing slash for the Next.js proxy URL (Next.js 308-redirects
  // trailing slashes away by default). The proxy route handler re-adds the
  // trailing slash when forwarding to the Go API.
  const normalized = path.endsWith('/') ? path.slice(0, -1) : path;
  const url = `/api/proxy${normalized}`;

  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    'X-Timezone': Intl.DateTimeFormat().resolvedOptions().timeZone,
    ...(options.headers as Record<string, string>),
  };

  // If the caller explicitly set Content-Type to something else (e.g. for
  // FormData uploads), remove our default so the browser can set the
  // multipart boundary automatically.
  if (options.body instanceof FormData) {
    delete headers['Content-Type'];
  }

  const res = await fetch(url, { ...options, headers });

  if (!res.ok) {
    const body = await res.json().catch(() => ({ error: 'Unknown error' }));
    throw new ApiError(
      res.status,
      body.message || body.error || 'Request failed',
      body.details,
    );
  }

  // Handle 204 No Content
  if (res.status === 204) return undefined as T;

  return res.json();
}

// ---------------------------------------------------------------------------
// Server-side fetcher  (for server components & route handlers)
// ---------------------------------------------------------------------------

/**
 * Server-side fetch that reads the auth token from the `honeydue-token` cookie
 * and calls the Go API directly (no proxy hop).
 *
 * Only use this inside:
 *   - `app/api/.../route.ts`  handlers
 *   - Server Components
 *   - Server Actions
 */
export async function serverFetch<T>(
  path: string,
  options: RequestInit = {},
): Promise<T> {
  // Dynamic import so this module can still be imported from client bundles
  // (the function itself should only be *called* on the server).
  const { cookies } = await import('next/headers');
  const cookieStore = await cookies();
  const token = cookieStore.get('honeydue-token')?.value;

  const normalized = path.endsWith('/') ? path : `${path}/`;
  const url = `${SERVER_API_URL}${normalized}`;

  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    'X-Timezone': 'UTC', // Server-side default; client overrides via proxy
    ...(options.headers as Record<string, string>),
  };

  if (token) {
    headers['Authorization'] = `Token ${token}`;
  }

  if (options.body instanceof FormData) {
    delete headers['Content-Type'];
  }

  const res = await fetch(url, {
    ...options,
    headers,
    // Disable Next.js fetch cache for mutations; callers can override.
    cache: options.cache ?? 'no-store',
  });

  if (!res.ok) {
    const body = await res.json().catch(() => ({ error: 'Unknown error' }));
    throw new ApiError(
      res.status,
      body.message || body.error || 'Request failed',
      body.details,
    );
  }

  if (res.status === 204) return undefined as T;

  return res.json();
}
