/**
 * Mirror Rank Math SEO + Open Graph + JSON-LD from the source WP HTML.
 * Phase 1 strategy: fetch the raw post URL on WP and extract <meta>, <link rel=canonical>, JSON-LD.
 * Phase 2 (future): switch to WPGraphQL Rank Math plugin if installed.
 */
import type { SeoMeta } from "./wp-types";

const WP_BASE = process.env.WP_BASE_URL ?? "https://finzone.io.vn";
const WP_INTERNAL_BASE = process.env.WP_INTERNAL_URL ?? WP_BASE;
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://new.finzone.io.vn";

const META_RE = /<meta\s+([^>]+?)\/?>/gi;
const LINK_RE = /<link\s+([^>]+?)\/?>/gi;
const JSONLD_RE = /<script[^>]+type=["']application\/ld\+json["'][^>]*>([\s\S]*?)<\/script>/gi;
const TITLE_RE = /<title>([\s\S]*?)<\/title>/i;

function parseAttrs(s: string): Record<string, string> {
  const out: Record<string, string> = {};
  const re = /(\w[\w:-]*)\s*=\s*"((?:[^"\\]|\\.)*)"/g;
  let m;
  while ((m = re.exec(s)) !== null) out[m[1]!.toLowerCase()] = m[2]!;
  return out;
}

function rewriteUrl(u: string | undefined, opts?: { keepMedia?: boolean }): string | undefined {
  if (!u) return u;
  try {
    const wp = new URL(WP_BASE);
    const target = new URL(u, wp);
    // Keep media URLs on WP (they live in /wp-content/uploads/)
    if (opts?.keepMedia && target.pathname.startsWith("/wp-content/")) {
      return u;
    }
    return u.split(wp.origin).join(SITE_URL);
  } catch {
    return u;
  }
}

export async function fetchSeoFromUrl(wpUrl: string, revalidate = 600): Promise<SeoMeta> {
  // Rewrite the public WP URL to the fast internal proxy when configured.
  // wpUrl looks like https://finzone.io.vn/some-slug/ — we rewrite the origin only.
  let targetUrl = wpUrl;
  try {
    const u = new URL(wpUrl);
    const internal = new URL(WP_INTERNAL_BASE);
    if (u.origin !== internal.origin) {
      targetUrl = internal.origin + u.pathname + u.search;
    }
  } catch {}
  try {
    const res = await fetch(targetUrl, {
      headers: { "User-Agent": "FinzoneFrontend/1.0 (+SEO mirror)" },
      next: { revalidate, tags: ["seo"] },
    });
    if (!res.ok) return {};
    const html = await res.text();
    return parseSeoHtml(html);
  } catch {
    return {};
  }
}

export function parseSeoHtml(html: string): SeoMeta {
  // Take only <head> portion to keep regex cheap
  const headEnd = html.indexOf("</head>");
  const head = headEnd > 0 ? html.slice(0, headEnd) : html;

  const seo: SeoMeta = { jsonLd: [] };

  // <title>
  const t = head.match(TITLE_RE);
  if (t) seo.title = decodeHtml(t[1]!.trim());

  // <meta>
  let m;
  while ((m = META_RE.exec(head)) !== null) {
    const a = parseAttrs(m[1]!);
    const name = a.name?.toLowerCase();
    const property = a.property?.toLowerCase();
    const content = a.content;
    if (!content) continue;
    if (name === "description") seo.description = decodeHtml(content);
    if (name === "robots") seo.robots = content;
    if (property === "og:title") seo.ogTitle = decodeHtml(content);
    if (property === "og:description") seo.ogDescription = decodeHtml(content);
    if (property === "og:image") seo.ogImage = rewriteUrl(content, { keepMedia: true });
    if (property === "og:type") seo.ogType = content;
    if (name === "twitter:card") seo.twitterCard = content;
  }
  META_RE.lastIndex = 0;

  // <link rel="canonical">
  let l;
  while ((l = LINK_RE.exec(head)) !== null) {
    const a = parseAttrs(l[1]!);
    if ((a.rel ?? "").toLowerCase() === "canonical" && a.href) {
      seo.canonical = rewriteUrl(a.href);
    }
  }
  LINK_RE.lastIndex = 0;

  // JSON-LD blocks
  let j;
  while ((j = JSONLD_RE.exec(html)) !== null) {
    const raw = j[1]!.trim();
    if (raw) seo.jsonLd!.push(rewriteJsonLd(raw));
  }
  JSONLD_RE.lastIndex = 0;

  return seo;
}

function rewriteJsonLd(raw: string): string {
  try {
    const wp = new URL(WP_BASE);
    // Replace finzone.io.vn → new.finzone.io.vn but NOT in media URLs.
    // Strategy: replace domain only when followed by anything except "/wp-content/" or "/wp-includes/".
    const re = new RegExp(
      wp.origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "(?!/wp-content/|/wp-includes/)",
      "g"
    );
    return raw.replace(re, SITE_URL);
  } catch {
    return raw;
  }
}

function decodeHtml(s: string): string {
  return s
    .replace(/&amp;/g, "&")
    .replace(/&lt;/g, "<")
    .replace(/&gt;/g, ">")
    .replace(/&quot;/g, '"')
    .replace(/&#039;/g, "'")
    .replace(/&apos;/g, "'");
}

/** Convert an article URL on WP to the matching new-site URL (slug-only permalink). */
export function wpUrlToSiteUrl(wpUrl: string): string {
  try {
    const u = new URL(wpUrl);
    return SITE_URL.replace(/\/$/, "") + u.pathname;
  } catch {
    return wpUrl;
  }
}
