/**
 * Thin fetch wrappers for the Page Organizer admin API.
 *
 * `fetchPage`   — GET /api/admin/page-layout/:page
 * `saveDraft`   — PUT /api/admin/page-layout/:page/draft
 *
 * `saveDraft` attaches `err.status` and `err.currentUpdatedAt` so callers can detect
 * and auto-recover from 409 self-race conflicts (two saves in-flight simultaneously).
 */

import { getCsrfToken } from '@/lib/csrf';
import { fetchWithRefresh } from '@/lib/api/refresh-on-401';

export interface FetchPageResult {
  liveVersion: {
    id: string;
    version: number;
    body: unknown;
    createdAt: string;
    note: string;
  };
  draft: { body: unknown; updatedAt: string } | null;
  scheduled: { versionId: string; at: string } | null;
  registry: Array<{
    type: string;
    category: string;
    labelKey: string;
    defaultConfig: unknown;
  }>;
}

export async function fetchPage(page: string): Promise<FetchPageResult> {
  const res = await fetchWithRefresh(`/api/admin/page-layout/${page}`);
  if (!res.ok) throw new Error(`fetchPage: ${res.status}`);
  const data = (await res.json()) as { ok: boolean; error?: string } & FetchPageResult;
  if (!data.ok) throw new Error(data.error ?? 'fetchPage: unknown error');
  return data;
}

export async function saveDraft(
  page: string,
  body: unknown,
  updatedAt: string | null,
): Promise<{ updatedAt: string }> {
  const res = await fetchWithRefresh(`/api/admin/page-layout/${page}/draft`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json', 'x-csrf-token': getCsrfToken() },
    body: JSON.stringify({ body, updatedAt }),
  });
  const data = (await res.json()) as {
    updatedAt?: string;
    error?: string;
    currentUpdatedAt?: string;
  };
  if (!res.ok) {
    const err = new Error(data.error ?? 'save failed') as Error & {
      status?: number;
      currentUpdatedAt?: string;
    };
    err.status = res.status;
    err.currentUpdatedAt = data.currentUpdatedAt;
    throw err;
  }
  return { updatedAt: data.updatedAt! };
}

/** POST /api/admin/page-layout/:page/publish */
export async function publish(
  page: string,
  payload: { note?: string },
): Promise<{ versionId: string; version: number }> {
  const res = await fetchWithRefresh(`/api/admin/page-layout/${page}/publish`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'x-csrf-token': getCsrfToken() },
    body: JSON.stringify(payload),
  });
  const data = (await res.json()) as {
    ok?: boolean;
    versionId?: string;
    version?: number;
    error?: string;
  };
  if (!res.ok || !data.ok) throw new Error(data.error ?? 'publish failed');
  return { versionId: data.versionId!, version: data.version! };
}

/** POST /api/admin/page-layout/:page/schedule */
export async function schedule(
  page: string,
  payload: { versionId: string; at: string },
): Promise<void> {
  const res = await fetchWithRefresh(`/api/admin/page-layout/${page}/schedule`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'x-csrf-token': getCsrfToken() },
    body: JSON.stringify(payload),
  });
  const data = (await res.json()) as { ok?: boolean; error?: string };
  if (!res.ok || !data.ok) throw new Error(data.error ?? 'schedule failed');
}

/** DELETE /api/admin/page-layout/:page/schedule */
export async function cancelSchedule(page: string): Promise<void> {
  const res = await fetchWithRefresh(`/api/admin/page-layout/${page}/schedule`, {
    method: 'DELETE',
    headers: { 'x-csrf-token': getCsrfToken() },
  });
  const data = (await res.json()) as { ok?: boolean; error?: string };
  if (!res.ok || !data.ok) throw new Error(data.error ?? 'cancel schedule failed');
}

export interface VersionRow {
  id: string;
  version: number;
  createdAt: string;
  createdBy: string | null;
  note: string | null;
}

/** GET /api/admin/page-layout/:page/versions */
export async function versions(page: string): Promise<VersionRow[]> {
  const res = await fetchWithRefresh(`/api/admin/page-layout/${page}/versions`);
  const data = (await res.json()) as { ok?: boolean; versions?: VersionRow[]; error?: string };
  if (!res.ok || !data.ok) throw new Error(data.error ?? 'versions failed');
  return data.versions!;
}

export interface PageEntry {
  slug: string;
  label: { he: string; en: string };
}

export async function fetchPages(): Promise<PageEntry[]> {
  const res = await fetchWithRefresh('/api/admin/page-layout');
  if (!res.ok) throw new Error(`fetchPages: ${res.status}`);
  const data = (await res.json()) as { ok: boolean; pages?: PageEntry[]; error?: string };
  if (!data.ok) throw new Error(data.error ?? 'fetchPages: unknown error');
  return data.pages!;
}

export interface PageMetadata {
  seo: {
    title: { he: string; en: string };
    description: { he: string; en: string };
    ogImage?: string;
  };
}

export async function saveMetadata(page: string, metadata: PageMetadata): Promise<void> {
  const res = await fetchWithRefresh(`/api/admin/page-layout/${page}/metadata`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json', 'x-csrf-token': getCsrfToken() },
    body: JSON.stringify(metadata),
  });
  const data = (await res.json()) as { ok?: boolean; error?: string };
  if (!res.ok || !data.ok) throw new Error(data.error ?? 'saveMetadata failed');
}

/** POST /api/admin/page-layout/:page/revert */
export async function revert(
  page: string,
  payload: { versionId: string; note?: string },
): Promise<{ versionId: string; version: number }> {
  const res = await fetchWithRefresh(`/api/admin/page-layout/${page}/revert`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'x-csrf-token': getCsrfToken() },
    body: JSON.stringify(payload),
  });
  const data = (await res.json()) as {
    ok?: boolean;
    versionId?: string;
    version?: number;
    error?: string;
  };
  if (!res.ok || !data.ok) throw new Error(data.error ?? 'revert failed');
  return { versionId: data.versionId!, version: data.version! };
}
