import type { WordpressCategory, WordpressContent, WordpressPage, WordpressPost } from "../content/types";

type WordpressConfig = {
  baseUrl: string;
  username?: string;
  appPassword?: string;
};

type FetchResult<T> = {
  data: T;
  totalPages?: number;
};

function stripHtml(input: string): string {
  return input.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
}

function decodeEntities(input: string): string {
  // Keep it small: enough for common WP fields.
  return input
    .replace(/&amp;/g, "&")
    .replace(/&lt;/g, "<")
    .replace(/&gt;/g, ">")
    .replace(/&quot;/g, '"')
    .replace(/&#039;/g, "'")
    .replace(/&#39;/g, "'");
}

function sanitizeHtml(input: string): string {
  // Remove script blocks entirely.
  return input.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
}

function getAuthHeaders(cfg: WordpressConfig): Record<string, string> {
  if (!cfg.username || !cfg.appPassword) return {};
  const token = Buffer.from(`${cfg.username}:${cfg.appPassword}`, "utf8").toString("base64");
  return { Authorization: `Basic ${token}` };
}

async function wpFetchJson<T>(url: string, headers: Record<string, string>): Promise<FetchResult<T>> {
  const res = await fetch(url, {
    headers: {
      Accept: "application/json",
      ...headers,
    },
    signal: AbortSignal.timeout(15000),
  });

  if (!res.ok) {
    throw new Error(`WP request failed: ${res.status} ${res.statusText} (${url})`);
  }

  const totalPagesRaw = res.headers.get("x-wp-totalpages");
  const totalPages = totalPagesRaw ? Number(totalPagesRaw) : undefined;
  const data = (await res.json()) as T;
  return { data, totalPages };
}

async function fetchAllPages<T>(
  urlForPage: (page: number) => string,
  headers: Record<string, string>,
): Promise<T[]> {
  const first = await wpFetchJson<T[]>(urlForPage(1), headers);
  const out = [...first.data];

  const total = first.totalPages && Number.isFinite(first.totalPages) ? first.totalPages : 1;
  for (let p = 2; p <= total; p++) {
    const pageRes = await wpFetchJson<T[]>(urlForPage(p), headers);
    out.push(...pageRes.data);
  }

  return out;
}

function wpUrl(baseUrl: string, path: string): string {
  return `${baseUrl.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
}

function mapFeaturedImageUrl(wpItem: any): string | undefined {
  const embedded = wpItem?._embedded;
  const media = embedded?.["wp:featuredmedia"];
  const first = Array.isArray(media) ? media[0] : undefined;
  const src = first?.source_url;
  return typeof src === "string" && src.length > 0 ? src : undefined;
}

function mapCategoryIds(wpItem: any): number[] {
  const ids = wpItem?.categories;
  return Array.isArray(ids) ? ids.filter((x) => typeof x === "number") : [];
}

export function normalizeWordpressPost(raw: any): WordpressPost {
  const titleHtml = raw?.title?.rendered || "";
  const excerptHtml = raw?.excerpt?.rendered || "";
  const contentHtml = raw?.content?.rendered || "";

  const title = decodeEntities(stripHtml(String(titleHtml)));
  const excerpt = decodeEntities(stripHtml(String(excerptHtml)));

  const date = typeof raw?.date_gmt === "string" && raw.date_gmt ? raw.date_gmt : raw?.date;
  const modified =
    typeof raw?.modified_gmt === "string" && raw.modified_gmt ? raw.modified_gmt : raw?.modified;

  return {
    id: String(raw?.id ?? raw?.slug ?? ""),
    kind: "post",
    slug: String(raw?.slug ?? ""),
    url: String(raw?.link ?? ""),
    title,
    excerpt,
    contentHtml: sanitizeHtml(String(contentHtml)),
    featuredImageUrl: mapFeaturedImageUrl(raw),
    publishedAt: new Date(date || 0).toISOString(),
    updatedAt: new Date(modified || date || 0).toISOString(),
    categoryIds: mapCategoryIds(raw),
  };
}

export function normalizeWordpressPage(raw: any): WordpressPage {
  const titleHtml = raw?.title?.rendered || "";
  const excerptHtml = raw?.excerpt?.rendered || "";
  const contentHtml = raw?.content?.rendered || "";

  const title = decodeEntities(stripHtml(String(titleHtml)));
  const excerpt = decodeEntities(stripHtml(String(excerptHtml)));

  const date = typeof raw?.date_gmt === "string" && raw.date_gmt ? raw.date_gmt : raw?.date;
  const modified =
    typeof raw?.modified_gmt === "string" && raw.modified_gmt ? raw.modified_gmt : raw?.modified;

  return {
    id: String(raw?.id ?? raw?.slug ?? ""),
    kind: "page",
    slug: String(raw?.slug ?? ""),
    url: String(raw?.link ?? ""),
    title,
    excerpt,
    contentHtml: sanitizeHtml(String(contentHtml)),
    featuredImageUrl: mapFeaturedImageUrl(raw),
    publishedAt: new Date(date || 0).toISOString(),
    updatedAt: new Date(modified || date || 0).toISOString(),
  };
}

export function normalizeWordpressCategory(raw: any): WordpressCategory {
  return {
    id: typeof raw?.id === "number" ? raw.id : Number(raw?.id ?? 0),
    slug: String(raw?.slug ?? ""),
    name: decodeEntities(stripHtml(String(raw?.name ?? ""))),
  };
}

export async function fetchWordpressContent(cfg: WordpressConfig): Promise<WordpressContent> {
  const headers = getAuthHeaders(cfg);

  // Default per_page max is often 100.
  const posts = await fetchAllPages<any>(
    (page) => wpUrl(cfg.baseUrl, `/wp-json/wp/v2/posts?per_page=100&page=${page}&_embed=1`),
    headers,
  );
  const pages = await fetchAllPages<any>(
    (page) => wpUrl(cfg.baseUrl, `/wp-json/wp/v2/pages?per_page=100&page=${page}&_embed=1`),
    headers,
  );
  const categories = await fetchAllPages<any>(
    (page) => wpUrl(cfg.baseUrl, `/wp-json/wp/v2/categories?per_page=100&page=${page}`),
    headers,
  );

  return {
    posts: posts.map(normalizeWordpressPost).filter((p) => p.slug && p.title),
    pages: pages.map(normalizeWordpressPage).filter((p) => p.slug && p.title),
    categories: categories.map(normalizeWordpressCategory).filter((c) => c.slug && c.name),
  };
}

