export const apiPrefix = import.meta.env.VITE_API_PREFIX || "";
export const apiBase = (import.meta.env.VITE_API_URL || "") + apiPrefix;

/** Go JSON encodes nil slices as null — normalize before .map() */
export function itemsOrEmpty<T>(items: T[] | null | undefined): T[] {
  return Array.isArray(items) ? items : [];
}

export function assetUrl(path: string | undefined | null) {
  if (!path) return "";
  if (path.startsWith("http")) return path;
  return `${apiBase}${path}`;
}

type JsonCacheEntry<T> = {
  cachedAt: number;
  value: T;
};

const jsonMemoryCache = new Map<string, JsonCacheEntry<unknown>>();
const jsonStoragePrefix = "ark-json-cache:v1:";

function jsonCacheKey(path: string): string {
  return `${apiBase}${path}`;
}

export function readJSONCache<T>(path: string): T | null {
  const key = jsonCacheKey(path);
  const memoryEntry = jsonMemoryCache.get(key) as JsonCacheEntry<T> | undefined;
  if (memoryEntry) return memoryEntry.value;

  if (typeof window === "undefined") return null;

  try {
    const raw = window.localStorage.getItem(`${jsonStoragePrefix}${key}`);
    if (!raw) return null;
    const entry = JSON.parse(raw) as JsonCacheEntry<T>;
    jsonMemoryCache.set(key, entry as JsonCacheEntry<unknown>);
    return entry.value;
  } catch {
    return null;
  }
}

function writeJSONCache<T>(path: string, value: T): void {
  const key = jsonCacheKey(path);
  const entry: JsonCacheEntry<T> = { cachedAt: Date.now(), value };
  jsonMemoryCache.set(key, entry as JsonCacheEntry<unknown>);

  if (typeof window === "undefined") return;

  try {
    window.localStorage.setItem(
      `${jsonStoragePrefix}${key}`,
      JSON.stringify(entry),
    );
  } catch {
    // Ignore storage quota / privacy-mode failures; memory cache still works.
  }
}

export async function getJSON<T>(path: string): Promise<T> {
  const res = await fetch(`${apiBase}${path}`);
  if (!res.ok) throw new Error(await res.text());
  const data = (await res.json()) as T;
  writeJSONCache(path, data);
  return data;
}

export async function getJSONAuth<T>(path: string, token: string): Promise<T> {
  const res = await fetch(`${apiBase}${path}`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json() as Promise<T>;
}

export async function postJSON<T>(
  path: string,
  body: unknown,
  token?: string,
): Promise<T> {
  const headers: Record<string, string> = {
    "Content-Type": "application/json",
  };
  if (token) headers.Authorization = `Bearer ${token}`;
  const res = await fetch(`${apiBase}${path}`, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json() as Promise<T>;
}

export async function postNoBody(path: string): Promise<void> {
  const res = await fetch(`${apiBase}${path}`, { method: "POST" });
  if (!res.ok) throw new Error(await res.text());
}

export async function putJSON<T>(
  path: string,
  body: unknown,
  token: string,
): Promise<T> {
  const res = await fetch(`${apiBase}${path}`, {
    method: "PUT",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify(body),
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json() as Promise<T>;
}

export async function del(path: string, token: string) {
  const res = await fetch(`${apiBase}${path}`, {
    method: "DELETE",
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!res.ok) throw new Error(await res.text());
}

export async function uploadFile(
  file: File,
  token: string,
): Promise<{ url: string }> {
  const fd = new FormData();
  fd.append("file", file);
  const res = await fetch(`${apiBase}/api/admin/upload`, {
    method: "POST",
    headers: { Authorization: `Bearer ${token}` },
    body: fd,
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json();
}

export type Category = {
  id: number;
  slug: string;
  name: string;
  description?: string;
  iconKey: string;
  sortOrder: number;
};

export type Resource = {
  id: string;
  title: string;
  description?: string;
  type: string;
  language: string;
  categoryId: number;
  categorySlug: string;
  categoryName: string;
  coverImage?: string;
  fileUrl?: string;
  previewUrl?: string;
  externalUrl?: string;
  bodyText?: string;
  badgeLabel?: string;
  isDownloadable: boolean;
  isRecommended: boolean;
  publishedAt?: string;
  updatedAt: string;
  tags?: string[];
};

export type AdminResource = Resource & {
  isPublic: boolean;
  sortOrder: number;
  status: string;
  publishedAt?: string;
  viewCount?: number;
  downloadCount?: number;
};
