import "server-only";

export type LinkedInProfile = {
  name?: string;
  designation?: string;
  organization?: string;
  bio?: string;
  photoUrl?: string;
  /** true when we could only derive data from the URL itself */
  partial: boolean;
};

export function normalizeLinkedInUrl(raw: string): string | null {
  try {
    const u = new URL(raw.trim());
    if (!/(^|\.)linkedin\.com$/.test(u.hostname)) return null;
    const m = u.pathname.match(/\/in\/([^/]+)/);
    if (!m) return null;
    return `https://www.linkedin.com/in/${decodeURIComponent(m[1]).replace(/\/$/, "")}`;
  } catch {
    return null;
  }
}

/** "dr-meera-krishnan-1a2b3c" → "Dr Meera Krishnan" */
export function nameFromSlug(url: string): string {
  const slug = url.split("/in/")[1] ?? "";
  return slug
    .split("-")
    .filter((p) => p && !/^\d/.test(p) && !/^[0-9a-f]{6,}$/i.test(p))
    .map((p) => p.charAt(0).toUpperCase() + p.slice(1))
    .join(" ")
    .trim();
}

function meta(html: string, property: string): string | undefined {
  const re = new RegExp(`<meta[^>]+(?:property|name)=["']${property}["'][^>]+content=["']([^"']+)["']`, "i");
  const alt = new RegExp(`<meta[^>]+content=["']([^"']+)["'][^>]+(?:property|name)=["']${property}["']`, "i");
  const raw = html.match(re)?.[1] ?? html.match(alt)?.[1];
  return raw
    ?.replace(/&amp;/g, "&").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">");
}

/** "Priya Sharma - CTO at PaySwift | LinkedIn" → parts */
function parseTitle(title: string): { name?: string; headline?: string } {
  const clean = title.replace(/\s*[|·]\s*LinkedIn\s*$/i, "").trim();
  const [name, ...rest] = clean.split(/\s+-\s+/);
  return { name: name?.trim() || undefined, headline: rest.join(" - ").trim() || undefined };
}

function splitHeadline(headline?: string): { designation?: string; organization?: string } {
  if (!headline) return {};
  const m = headline.match(/^(.*?)\s+(?:at|@)\s+(.+)$/i);
  if (m) return { designation: m[1].trim(), organization: m[2].trim() };
  return { designation: headline.trim() };
}

/**
 * Best-effort public-profile scrape: og: tags and JSON-LD when LinkedIn serves
 * them to logged-out crawlers; otherwise falls back to the URL slug.
 */
export async function fetchLinkedInProfile(url: string): Promise<LinkedInProfile> {
  const fallback: LinkedInProfile = { name: nameFromSlug(url) || undefined, partial: true };
  try {
    const res = await fetch(url, {
      headers: {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36",
        Accept: "text/html,application/xhtml+xml",
        "Accept-Language": "en-US,en;q=0.9",
      },
      redirect: "follow",
      signal: AbortSignal.timeout(9000),
    });
    const html = await res.text();
    if (!res.ok || /authwall|uas\/login|sign in to linkedin/i.test(html.slice(0, 4000))) return fallback;

    const out: LinkedInProfile = { ...fallback, partial: false };

    // JSON-LD Person block (richest source when present)
    const ld = html.match(/<script type=["']application\/ld\+json["']>([\s\S]*?)<\/script>/i)?.[1];
    if (ld) {
      try {
        const data = JSON.parse(ld);
        const person = [data, ...(Array.isArray(data["@graph"]) ? data["@graph"] : [])].find(
          (n) => n && (n["@type"] === "Person" || (Array.isArray(n["@type"]) && n["@type"].includes("Person")))
        );
        if (person) {
          out.name = person.name ?? out.name;
          out.designation = person.jobTitle?.[0] ?? (typeof person.jobTitle === "string" ? person.jobTitle : undefined);
          out.organization = person.worksFor?.[0]?.name ?? person.worksFor?.name;
          out.bio = typeof person.description === "string" ? person.description.slice(0, 600) : undefined;
          out.photoUrl = person.image?.contentUrl ?? (typeof person.image === "string" ? person.image : undefined);
        }
      } catch { /* malformed JSON-LD — continue with og tags */ }
    }

    const ogTitle = meta(html, "og:title");
    if (ogTitle) {
      const { name, headline } = parseTitle(ogTitle);
      out.name = out.name && !out.partial ? out.name : name ?? out.name;
      if (!out.designation && headline) Object.assign(out, splitHeadline(headline));
    }
    if (!out.bio) {
      const desc = meta(html, "og:description");
      if (desc) out.bio = desc.slice(0, 600);
    }
    if (!out.photoUrl) out.photoUrl = meta(html, "og:image");

    return out.name ? out : fallback;
  } catch {
    return fallback;
  }
}
