import Constants from "expo-constants";
import { useAuth } from "./auth";

/**
 * API-klient. Mobilappen pratar ENDAST med Food API – aldrig direkt med
 * modelleverantörer, och innehåller inga AI-hemligheter (spec §31, §61.13).
 * 401 → automatisk refresh med roterande token → retry en gång.
 */

const API_BASE =
  (Constants.expoConfig?.extra as { apiBaseUrl?: string } | undefined)?.apiBaseUrl ??
  "http://localhost:4000";

export class ApiError extends Error {
  constructor(
    public readonly status: number,
    public readonly code: string,
    message: string,
    public readonly details?: unknown,
  ) {
    super(message);
  }
}

let refreshPromise: Promise<boolean> | null = null;

async function tryRefresh(): Promise<boolean> {
  if (!refreshPromise) {
    refreshPromise = (async () => {
      const { getRefreshToken, setSession, logout } = useAuth.getState();
      const refreshToken = await getRefreshToken();
      if (!refreshToken) return false;
      try {
        const res = await fetch(`${API_BASE}/v1/auth/refresh`, {
          method: "POST",
          headers: { "content-type": "application/json" },
          body: JSON.stringify({ refreshToken }),
        });
        if (!res.ok) {
          await logout();
          return false;
        }
        const json = (await res.json()) as { accessToken: string; refreshToken: string };
        await setSession(
          { accessToken: json.accessToken, refreshToken: json.refreshToken },
          useAuth.getState().user,
        );
        return true;
      } catch {
        return false;
      } finally {
        setTimeout(() => {
          refreshPromise = null;
        }, 100);
      }
    })();
  }
  return refreshPromise;
}

export async function api<T = unknown>(
  path: string,
  options: { method?: string; body?: unknown; retry?: boolean } = {},
): Promise<T> {
  const { accessToken } = useAuth.getState();
  const res = await fetch(`${API_BASE}${path}`, {
    method: options.method ?? "GET",
    headers: {
      "content-type": "application/json",
      ...(accessToken ? { authorization: `Bearer ${accessToken}` } : {}),
    },
    body: options.body != null ? JSON.stringify(options.body) : undefined,
  });

  if (res.status === 401 && options.retry !== false) {
    const refreshed = await tryRefresh();
    if (refreshed) return api<T>(path, { ...options, retry: false });
  }

  const json = (await res.json().catch(() => ({}))) as {
    error?: { code?: string; message?: string; details?: unknown };
  };
  if (!res.ok) {
    throw new ApiError(
      res.status,
      json.error?.code ?? "UNKNOWN",
      json.error?.message ?? `HTTP ${res.status}`,
      json.error?.details,
    );
  }
  return json as T;
}

/** Ladda upp en bild till en presignad URL (mock-S3 i dev, riktig S3 i prod). */
export async function uploadImage(
  upload: { uploadUrl: string; headers: Record<string, string> },
  localUri: string,
): Promise<void> {
  const blob = await (await fetch(localUri)).blob();
  const res = await fetch(upload.uploadUrl, {
    method: "PUT",
    headers: upload.headers,
    body: blob,
  });
  if (!res.ok) throw new ApiError(res.status, "UPLOAD_FAILED", "Bilduppladdningen misslyckades.");
}

export { API_BASE };
