import { describe, expect, test } from "bun:test";
import type { Page, RunReport } from "./report";
import { teaserOf, verdictOf, verdictOfCounters } from "./report";

/**
 * A run the binary really produced, reduced to what the verdict reads.
 *
 * `summary.checked` and `discovery.checked` are two different counts and the
 * distinction is the whole point of these tests: the contract (§4.4) says a
 * page whose outcome is `redirect` or `not-html` counts in none of the summary
 * counters, while `discovery.checked` counts every URL the run processed.
 */
function run(over: {
  pages: Page[];
  summaryChecked: number;
  discoveryChecked: number;
  blocking?: number;
  warnings?: number;
}): RunReport {
  return {
    tool: "nextjs-seo-prerender",
    version: "0.1.0",
    checked_at_unix: 0,
    interrupted: false,
    notes: [],
    fatal: null,
    site: "https://elevaseo.com",
    discovery: { source: "https://elevaseo.com/sitemap.xml", total: 350, checked: over.discoveryChecked },
    pages: over.pages,
    summary: {
      checked: over.summaryChecked,
      dynamic: 0,
      unclear: 0,
      noindex_header: 0,
      hreflang_drift: 0,
      hreflang_dead_target: 0,
      empty_html: 0,
      sitemap_errors: 0,
      unreachable: 0,
      blocking: over.blocking ?? 0,
    },
    warnings: over.warnings ?? 0,
    exit_code: (over.blocking ?? 0) > 0 ? 1 : 0,
  };
}

function redirects(n: number): Page[] {
  return Array.from({ length: n }, (_, i) => ({
    url: `https://elevaseo.com/page-${i}`,
    outcome: "redirect" as const,
    status: 308,
    findings: [{ kind: "sitemap-url-redirect", severity: "info" as const, message: "redirigée" }],
  }));
}

function checked(n: number, findings: Page["findings"] = []): Page[] {
  return Array.from({ length: n }, (_, i) => ({
    url: `https://www.elevaseo.com/page-${i}`,
    outcome: "checked" as const,
    status: 200,
    findings,
  }));
}

describe("a run where nothing could be verified", () => {
  // The case that shipped a green verdict: elevaseo.com serves a sitemap of
  // www URLs, the tool rebases them onto the apex, and the apex answers 308 to
  // every one of them. Ten pages processed, none audited.
  const wall = run({ pages: redirects(10), summaryChecked: 0, discoveryChecked: 10 });

  test("does not read as clean", () => {
    expect(verdictOf(wall)).toBe("unverified");
  });

  test("counts the pages it verified, not the ones it fetched", () => {
    expect(teaserOf(wall).checked).toBe(0);
  });

  test("is the same reading from the stored columns", () => {
    expect(verdictOfCounters({ exitCode: 0, blocking: 0, warnings: 0, checked: 0 })).toBe("unverified");
  });
});

describe("a run that verified something", () => {
  test("keeps its blocking verdict", () => {
    const report = run({ pages: checked(10), summaryChecked: 10, discoveryChecked: 10, blocking: 17 });
    expect(verdictOf(report)).toBe("blocking");
    expect(teaserOf(report).checked).toBe(10);
  });

  test("keeps its warned verdict", () => {
    const report = run({ pages: checked(10), summaryChecked: 10, discoveryChecked: 10, warnings: 1 });
    expect(verdictOf(report)).toBe("warned");
  });

  test("keeps its clean verdict", () => {
    const report = run({ pages: checked(10), summaryChecked: 10, discoveryChecked: 10 });
    expect(verdictOf(report)).toBe("clean");
  });
});

describe("a run that reached nothing at all", () => {
  // Unreachable pages count in no summary counter either, but the tool files a
  // blocking finding for each — so the verdict has something true to say and
  // "unverified" would bury it.
  test("prefers the blocking verdict over the empty one", () => {
    const report = run({
      pages: checked(0),
      summaryChecked: 0,
      discoveryChecked: 10,
      blocking: 10,
    });
    expect(verdictOf(report)).toBe("blocking");
    expect(verdictOfCounters({ exitCode: 1, blocking: 10, warnings: 0, checked: 0 })).toBe("blocking");
  });
});
