import { describe, expect, test } from "bun:test";
import { computeIssues } from "./issues";
import type { CrawledPage } from "./types";

/** Page saine par défaut (aucune issue) ; surchargée champ par champ. */
function page(over: Partial<CrawledPage> = {}): CrawledPage {
  return {
    url: "https://ex.com/produit/bague-or",
    status: 200,
    title: "Bague en or 18 carats — bijouterie",
    metaDescription:
      "Découvrez notre bague en or 18 carats, fabriquée en France, livrée sous 48h avec garantie.",
    h1: "Bague en or 18 carats",
    h1Count: 1,
    canonical: "https://ex.com/produit/bague-or",
    robots: "index,follow",
    lang: "fr",
    wordCount: 320,
    ...over,
  };
}

describe("computeIssues — page saine", () => {
  test("aucune issue", () => {
    expect(computeIssues(page())).toEqual([]);
  });

  test("canonical vide toléré (pas de mismatch)", () => {
    expect(computeIssues(page({ canonical: null }))).toEqual([]);
    expect(computeIssues(page({ canonical: "   " }))).toEqual([]);
  });
});

describe("computeIssues — title", () => {
  test("title-missing (null / vide)", () => {
    expect(computeIssues(page({ title: null }))).toContain("title-missing");
    expect(computeIssues(page({ title: "   " }))).toContain("title-missing");
  });
  test("title-long > 60", () => {
    expect(computeIssues(page({ title: "x".repeat(61) }))).toContain(
      "title-long",
    );
    expect(computeIssues(page({ title: "x".repeat(60) }))).not.toContain(
      "title-long",
    );
  });
  test("title-short < 15", () => {
    expect(computeIssues(page({ title: "x".repeat(14) }))).toContain(
      "title-short",
    );
    expect(computeIssues(page({ title: "x".repeat(15) }))).not.toContain(
      "title-short",
    );
  });
});

describe("computeIssues — description", () => {
  test("description-missing", () => {
    expect(computeIssues(page({ metaDescription: null }))).toContain(
      "description-missing",
    );
  });
  test("description-long > 160", () => {
    expect(computeIssues(page({ metaDescription: "x".repeat(161) }))).toContain(
      "description-long",
    );
    expect(
      computeIssues(page({ metaDescription: "x".repeat(160) })),
    ).not.toContain("description-long");
  });
  test("description-short < 50", () => {
    expect(computeIssues(page({ metaDescription: "x".repeat(49) }))).toContain(
      "description-short",
    );
    expect(
      computeIssues(page({ metaDescription: "x".repeat(50) })),
    ).not.toContain("description-short");
  });
});

describe("computeIssues — h1", () => {
  test("h1-missing (null / vide)", () => {
    expect(computeIssues(page({ h1: null, h1Count: 0 }))).toContain(
      "h1-missing",
    );
    expect(computeIssues(page({ h1: "  ", h1Count: 0 }))).toContain(
      "h1-missing",
    );
  });
  test("h1-multiple quand h1Count > 1", () => {
    expect(computeIssues(page({ h1Count: 2 }))).toContain("h1-multiple");
    expect(computeIssues(page({ h1Count: 1 }))).not.toContain("h1-multiple");
  });
});

describe("computeIssues — robots / canonical / status", () => {
  test("noindex (insensible casse, dans une liste)", () => {
    expect(computeIssues(page({ robots: "noindex,follow" }))).toContain(
      "noindex",
    );
    expect(computeIssues(page({ robots: "NoIndex" }))).toContain("noindex");
  });
  test("canonical-mismatch quand canonical normalisée ≠ url", () => {
    expect(
      computeIssues(page({ canonical: "https://ex.com/autre" })),
    ).toContain("canonical-mismatch");
  });
  test("canonical avec trailing slash normalise identique → pas de mismatch", () => {
    expect(
      computeIssues(page({ canonical: "https://ex.com/produit/bague-or/" })),
    ).not.toContain("canonical-mismatch");
  });
  test("error si status >= 400", () => {
    expect(computeIssues(page({ status: 404 }))).toContain("error");
    expect(computeIssues(page({ status: 500 }))).toContain("error");
  });
  test("error si status === 0", () => {
    expect(computeIssues(page({ status: 0 }))).toContain("error");
  });
  test("status 3xx pas d'error", () => {
    expect(computeIssues(page({ status: 301 }))).not.toContain("error");
  });
});

describe("computeIssues — cumul", () => {
  test("page morte et vide cumule plusieurs issues", () => {
    const res = computeIssues(
      page({
        status: 0,
        title: null,
        metaDescription: null,
        h1: null,
        h1Count: 0,
        canonical: null,
        robots: "noindex",
      }),
    );
    expect(res).toEqual(
      expect.arrayContaining([
        "title-missing",
        "description-missing",
        "h1-missing",
        "noindex",
        "error",
      ]),
    );
  });
});
