// src/lib/keywords/onpage.ts — pure OnpageDoc → on-page SerpCompetitor fields
// mapping, consumed by the Firecrawl-backed `crawl-onpage` worker
// (services/analytics/src/crawl-onpage.ts). The direct in-house fetch
// (`crawlOnpage`, once wired to `serp-actions.ts`) was removed once the
// worker took over the crawl (Task 5/6 — cf. docs/project/imports-follow-ups.md).
import {
  capMarkdown,
  outlineFromMarkdown,
  wordCountFromMarkdown,
} from "./markdown-analysis";
import type { HeadingNode, ImageAlt, SerpCompetitor } from "./serp-types";

/** Shape returned by `wasm.parse_onpage_document` (camelCase via serde). */
export interface OnpageDoc {
  title: string | null;
  description: string | null;
  language: string | null;
  markdown: string | null;
  images: number;
  imagesWithoutAlt: number;
  imageAlts: ImageAlt[];
  missingAltSrcs: string[];
  hasJsonLd: boolean;
  jsonLdTypes: string[];
}

export type OnpageFields = Pick<
  SerpCompetitor,
  | "title"
  | "metaDescription"
  | "lang"
  | "images"
  | "imagesWithoutAlt"
  | "imageAlts"
  | "missingAltSrcs"
  | "hasJsonLd"
  | "jsonLdTypes"
  | "markdown"
  | "wordCount"
  | "hnOutline"
  | "crawledAt"
>;

const CAP = 50;

/**
 * Pure document → OnpageFields mapping (no network, no wasm). Extracted so it
 * can be unit-tested without mock.module (which leaks globally across bun
 * test files).
 */
export function onpageFieldsFromDocument(
  doc: OnpageDoc,
  crawledAt: string,
): OnpageFields {
  const md = doc.markdown;
  const markdown: string | null = md ? capMarkdown(md) : null;
  const wordCount: number | null = md ? wordCountFromMarkdown(md) : null;
  const hnOutline: HeadingNode[] | null = md ? outlineFromMarkdown(md) : null;
  return {
    title: doc.title,
    metaDescription: doc.description,
    lang: doc.language,
    images: doc.images,
    imagesWithoutAlt: doc.imagesWithoutAlt,
    imageAlts: doc.imageAlts.slice(0, CAP),
    missingAltSrcs: doc.missingAltSrcs.slice(0, CAP),
    hasJsonLd: doc.hasJsonLd,
    jsonLdTypes: doc.jsonLdTypes,
    markdown,
    wordCount,
    hnOutline,
    crawledAt,
  };
}
