import { describe, test } from "node:test";
import assert from "node:assert/strict";

import { mintContentId } from "../src/id.js";
import type { PublishedRecord } from "../src/ingest.js";
import { assemblePostGraph, type AnalyticsRowInput } from "../src/assemble.js";

const DATE = "2026-05-26";

function rec(body: string, over: Partial<PublishedRecord> = {}): PublishedRecord {
  return {
    id: mintContentId(body),
    provenance: "published",
    published_date: DATE,
    captured_at: "2026-06-23",
    source: "manual",
    specifics: [],
    trends: [],
    body,
    ...over,
  };
}

function row(title: string, over: Partial<AnalyticsRowInput> = {}): AnalyticsRowInput {
  return { title, publishedDate: DATE, metrics: { engagementRate: 4.2 }, ...over };
}

// A body whose normalized opener is ≥ PREFIX_FLOOR (24) chars.
const BODY = "Jeg lærte noe viktig om dømmekraft i dag.\n\nDel 1 av serien.";
const FULL_TITLE = "Jeg lærte noe viktig om dømmekraft i dag.";

describe("SB-S3c assembler — assemblePostGraph (SC6/SC7/SC8)", () => {
  // SC6 — high confidence: body begins with the row title (≥floor) + same date.
  test("SC6: prefix-match + same date → high, whole row attached, specifics/trends surfaced", () => {
    const r = rec(BODY, { specifics: ["aaaaaaaaaaaa"], trends: ["bbbbbbbbbbbb"] });
    const graph = assemblePostGraph({ records: [r], analytics: [row(FULL_TITLE)] });
    assert.equal(graph.length, 1);
    assert.equal(graph[0].contentId, r.id);
    assert.equal(graph[0].match.confidence, "high");
    assert.deepEqual(graph[0].match.row, row(FULL_TITLE)); // the whole row reference (FIX 4)
    assert.deepEqual(graph[0].specifics, ["aaaaaaaaaaaa"]);
    assert.deepEqual(graph[0].trends, ["bbbbbbbbbbbb"]);
  });

  // SC7 — low / none / below-floor / ellipsis near-miss.
  test("SC7a: no prefix match → none", () => {
    const graph = assemblePostGraph({
      records: [rec(BODY)],
      analytics: [row("Completely unrelated opening sentence here")],
    });
    assert.equal(graph[0].match.confidence, "none");
    assert.equal(graph[0].match.row, undefined);
  });

  test("SC7b: a too-short (< floor) title that is a literal prefix → none (floor guards false high)", () => {
    const graph = assemblePostGraph({ records: [rec(BODY)], analytics: [row("Jeg lærte")] });
    assert.equal(graph[0].match.confidence, "none");
  });

  test("SC7c: a LinkedIn-truncated '…' title + same date → high (ellipsis stripped)", () => {
    const graph = assemblePostGraph({
      records: [rec(BODY)],
      analytics: [row("Jeg lærte noe viktig om dømmekraft i…")],
    });
    assert.equal(graph[0].match.confidence, "high");
  });

  test("SC7d: prefix match but a different date → low (surfaced, not hidden)", () => {
    const graph = assemblePostGraph({
      records: [rec(BODY)],
      analytics: [row(FULL_TITLE, { publishedDate: "2026-05-20" })],
    });
    assert.equal(graph[0].match.confidence, "low");
    assert.ok(graph[0].match.row, "row still attached on a low match");
  });

  // SC8 — pure + total.
  test("SC8: empty records → empty graph", () => {
    assert.deepEqual(assemblePostGraph({ records: [], analytics: [row(FULL_TITLE)] }), []);
  });

  test("SC8: empty analytics → every post present with match none, no throw", () => {
    const graph = assemblePostGraph({ records: [rec(BODY), rec("another post body here")], analytics: [] });
    assert.equal(graph.length, 2);
    assert.ok(graph.every((g) => g.match.confidence === "none"));
  });

  test("SC8: best-of prefers high over low and is deterministic", () => {
    const r = rec(BODY);
    const high = row(FULL_TITLE); // same date
    const low = row(FULL_TITLE, { publishedDate: "2026-01-01" }); // different date
    const graph = assemblePostGraph({ records: [r], analytics: [low, high] });
    assert.equal(graph[0].match.confidence, "high", "high beats low regardless of input order");
  });
});
