/**
 * 외부 URL의 HTML에서 Open Graph / Twitter 카드 이미지 URL 추출 (link.ncue.net 등과 유사한 미리보기)
 */

const OG_FETCH_TIMEOUT_MS = 15000;
const DEFAULT_UA =
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";

function decodeBasicHtmlEntities(s) {
  return (s || "")
    .replace(/&amp;/g, "&")
    .replace(/&quot;/g, '"')
    .replace(/&#39;/g, "'")
    .replace(/&lt;/g, "<")
    .replace(/&gt;/g, ">");
}

function resolveUrl(src, baseHref) {
  try {
    const t = (src || "").trim();
    if (!t) return null;
    return new URL(t, baseHref).href;
  } catch {
    return null;
  }
}

function extractOgImageFromHtml(html) {
  if (!html || typeof html !== "string") return null;
  const patterns = [
    /<meta\s[^>]*property=["']og:image["'][^>]*content=["']([^"']+)["']/i,
    /<meta\s[^>]*content=["']([^"']+)["'][^>]*property=["']og:image["']/i,
    /<meta\s[^>]*name=["']twitter:image:src["'][^>]*content=["']([^"']+)["']/i,
    /<meta\s[^>]*content=["']([^"']+)["'][^>]*name=["']twitter:image:src["']/i,
    /<meta\s[^>]*name=["']twitter:image["'][^>]*content=["']([^"']+)["']/i,
    /<meta\s[^>]*content=["']([^"']+)["'][^>]*name=["']twitter:image["']/i,
  ];
  for (const p of patterns) {
    const m = html.match(p);
    if (m && m[1]) return decodeBasicHtmlEntities(m[1].trim());
  }
  return null;
}

/**
 * @param {string} pageUrl
 * @returns {Promise<string|null>} 절대 URL의 og:image, 없으면 null
 */
async function fetchOpenGraphImageUrl(pageUrl) {
  const normalized = (pageUrl || "").trim();
  if (!normalized) return null;
  let base;
  try {
    base = new URL(normalized);
  } catch {
    return null;
  }
  if (base.protocol !== "http:" && base.protocol !== "https:") return null;

  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), OG_FETCH_TIMEOUT_MS);
  try {
    const res = await fetch(base.href, {
      redirect: "follow",
      signal: controller.signal,
      headers: {
        "User-Agent": DEFAULT_UA,
        Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
      },
    });
    if (!res.ok) return null;
    const ct = (res.headers.get("content-type") || "").toLowerCase();
    if (!ct.includes("text/html") && !ct.includes("application/xhtml")) {
      return null;
    }
    const html = await res.text();
    const raw = extractOgImageFromHtml(html);
    if (!raw) return null;
    const abs = resolveUrl(raw, base.href);
    if (!abs) return null;
    let imgUrl;
    try {
      imgUrl = new URL(abs);
    } catch {
      return null;
    }
    if (imgUrl.protocol !== "http:" && imgUrl.protocol !== "https:") return null;
    return imgUrl.href;
  } catch {
    return null;
  } finally {
    clearTimeout(timer);
  }
}

module.exports = { fetchOpenGraphImageUrl };
