/**
 * API Client for Layouts REST endpoints.
 *
 * Provides typed functions for communicating with the WordPress REST API.
 */

import type { PriceScenario, CanvasState, LayoutLocation } from "@/types";

/**
 * Get the REST API base URL
 */
const getApiUrl = (): string => {
  return window.oppbAdmin?.apiUrl ?? "/wp-json/opus-price-builder/v1";
};

/**
 * Get the REST API nonce for authentication
 */
const getNonce = (): string => {
  return window.oppbAdmin?.nonce ?? "";
};

/**
 * Available locations from API
 */
export type AvailableLocations = Record<string, string>;

/**
 * Layout data as returned by the API
 */
export interface Layout {
  id: number;
  name: string;
  slug: string;
  scenario: PriceScenario;
  // Location-based activation (flexible, dynamic)
  activeLocations: Record<string, boolean>;
  canvasData: CanvasState;
  settingsData: Record<string, unknown>;
  exportedHtml: string;
  exportedCss: string;
  exportedJs: string;
  createdAt: string;
  updatedAt: string;
}

/**
 * Data for creating a new layout
 */
export interface CreateLayoutData {
  name: string;
  slug?: string;
  scenario: PriceScenario;
  activeLocations?: Record<string, boolean>;
  canvasData?: CanvasState | string;
  settingsData?: Record<string, unknown> | string;
  exportedHtml?: string;
  exportedCss?: string;
  exportedJs?: string;
}

/**
 * Data for updating a layout
 */
export interface UpdateLayoutData extends Partial<CreateLayoutData> {
  id: number;
}

/**
 * Data for activating a layout for a location
 */
export interface ActivateLocationData {
  id: number;
  location: LayoutLocation;
  active: boolean;
}

/**
 * Query parameters for listing layouts
 */
export interface LayoutsQueryParams {
  page?: number;
  perPage?: number;
  search?: string;
  scenario?: PriceScenario;
  orderby?: "id" | "name" | "created_at" | "updated_at";
  order?: "ASC" | "DESC";
}

/**
 * Paginated response with headers
 */
export interface PaginatedResponse<T> {
  data: T[];
  total: number;
  totalPages: number;
}

/**
 * Active layouts by location for a single scenario
 */
export type ActiveLayoutsByLocation = Record<LayoutLocation, Layout | null>;

/**
 * Active layouts for all scenarios
 */
export type AllActiveLayouts = Record<PriceScenario, ActiveLayoutsByLocation>;

/**
 * API Error class
 */
export class ApiError extends Error {
  status: number;
  code: string;

  constructor(message: string, status: number, code: string) {
    super(message);
    this.name = "ApiError";
    this.status = status;
    this.code = code;
  }
}

/**
 * Make a fetch request with proper headers
 */
async function apiFetch<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
  const url = `${getApiUrl()}${endpoint}`;
  const nonce = getNonce();

  const response = await fetch(url, {
    ...options,
    headers: {
      "Content-Type": "application/json",
      "X-WP-Nonce": nonce,
      ...options.headers,
    },
  });

  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    throw new ApiError(error.message || "An error occurred", response.status, error.code || "unknown_error");
  }

  return response.json();
}

/**
 * Make a fetch request that returns paginated data
 */
async function apiFetchPaginated<T>(endpoint: string, options: RequestInit = {}): Promise<PaginatedResponse<T>> {
  const url = `${getApiUrl()}${endpoint}`;
  const nonce = getNonce();

  const response = await fetch(url, {
    ...options,
    headers: {
      "Content-Type": "application/json",
      "X-WP-Nonce": nonce,
      ...options.headers,
    },
  });

  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    throw new ApiError(error.message || "An error occurred", response.status, error.code || "unknown_error");
  }

  const data = await response.json();
  const total = parseInt(response.headers.get("X-WP-Total") || "0", 10);
  const totalPages = parseInt(response.headers.get("X-WP-TotalPages") || "0", 10);

  return {
    data,
    total,
    totalPages,
  };
}

// ============================================
// Layout API Functions
// ============================================

/**
 * Get all layouts with optional filtering
 */
export async function getLayouts(params: LayoutsQueryParams = {}): Promise<PaginatedResponse<Layout>> {
  const searchParams = new URLSearchParams();

  if (params.page) searchParams.set("page", params.page.toString());
  if (params.perPage) searchParams.set("per_page", params.perPage.toString());
  if (params.search) searchParams.set("search", params.search);
  if (params.scenario) searchParams.set("scenario", params.scenario);
  if (params.orderby) searchParams.set("orderby", params.orderby);
  if (params.order) searchParams.set("order", params.order);

  const query = searchParams.toString();
  const endpoint = `/layouts${query ? `?${query}` : ""}`;

  return apiFetchPaginated<Layout>(endpoint);
}

/**
 * Get a single layout by ID
 */
export async function getLayout(id: number): Promise<Layout> {
  return apiFetch<Layout>(`/layouts/${id}`);
}

/**
 * Create a new layout
 */
export async function createLayout(data: CreateLayoutData): Promise<Layout> {
  return apiFetch<Layout>("/layouts", {
    method: "POST",
    body: JSON.stringify({
      name: data.name,
      slug: data.slug,
      scenario: data.scenario,
      active_locations: data.activeLocations,
      canvas_data: data.canvasData,
    }),
  });
}

/**
 * Update an existing layout
 */
export async function updateLayout(data: UpdateLayoutData): Promise<Layout> {
  const { id, ...updateData } = data;

  // Convert camelCase to snake_case for API
  const body: Record<string, unknown> = {};
  if (updateData.name !== undefined) body.name = updateData.name;
  if (updateData.slug !== undefined) body.slug = updateData.slug;
  if (updateData.scenario !== undefined) body.scenario = updateData.scenario;
  if (updateData.canvasData !== undefined) body.canvas_data = updateData.canvasData;
  if (updateData.activeLocations !== undefined) body.active_locations = updateData.activeLocations;

  return apiFetch<Layout>(`/layouts/${id}`, {
    method: "PUT",
    body: JSON.stringify(body),
  });
}

/**
 * Delete a layout
 */
export async function deleteLayout(id: number): Promise<{ deleted: boolean; id: number }> {
  return apiFetch<{ deleted: boolean; id: number }>(`/layouts/${id}`, {
    method: "DELETE",
  });
}

/**
 * Duplicate a layout
 */
export async function duplicateLayout(id: number): Promise<Layout> {
  return apiFetch<Layout>(`/layouts/${id}/duplicate`, {
    method: "POST",
  });
}

/**
 * Activate or deactivate a layout for a specific location
 */
export async function activateLayoutForLocation(data: ActivateLocationData): Promise<Layout> {
  return apiFetch<Layout>(`/layouts/${data.id}/activate-location`, {
    method: "PUT",
    body: JSON.stringify({
      location: data.location,
      active: data.active,
    }),
  });
}

/**
 * Get all active layouts for all scenarios and locations
 */
export async function getActiveLayouts(): Promise<AllActiveLayouts> {
  return apiFetch<AllActiveLayouts>("/layouts/active");
}

/**
 * Get all available locations (can be extended via apply_filters on backend)
 */
export async function getLocations(): Promise<AvailableLocations> {
  return apiFetch<AvailableLocations>("/layouts/locations");
}
