import { describe, expect, it } from "vitest";
import { sanitizeHtml } from "./sanitize.js";

// The vitest environment is jsdom, so `window` is defined.
// DOMPurify will operate in client mode and strip tags.

describe("sanitizeHtml", () => {
  it("returns plain text unchanged", () => {
    expect(sanitizeHtml("Hello, World!")).toBe("Hello, World!");
  });

  it("strips a single HTML tag", () => {
    expect(sanitizeHtml("<b>bold</b>")).toBe("bold");
  });

  it("strips nested HTML tags", () => {
    expect(sanitizeHtml("<div><p>text</p></div>")).toBe("text");
  });

  it("strips attributes", () => {
    expect(sanitizeHtml('<a href="https://example.com">link</a>')).toBe("link");
  });

  it("strips script tags and their content", () => {
    // DOMPurify removes script tags entirely (content too)
    const result = sanitizeHtml('<script>alert("xss")</script>safe');
    expect(result).not.toContain("<script>");
    expect(result).not.toContain("alert");
    expect(result).toContain("safe");
  });

  it("strips event handler attributes", () => {
    const result = sanitizeHtml('<img src="x" onerror="alert(1)">');
    expect(result).not.toContain("onerror");
    expect(result).not.toContain("alert");
  });

  it("returns empty string for empty input", () => {
    expect(sanitizeHtml("")).toBe("");
  });

  it("passes through text that contains HTML entities", () => {
    // DOMPurify in jsdom returns the serialised form, keeping '&amp;' as-is
    // (it is not the job of sanitiseHtml to decode entities)
    const result = sanitizeHtml("&amp;");
    expect(result).toBeTruthy();
    // Either decoded ('&') or kept encoded ('&amp;') is acceptable; the
    // important thing is that no HTML tags survive.
    expect(result).not.toContain("<");
    expect(result).not.toContain(">");
  });

  it("strips style tags", () => {
    const result = sanitizeHtml("<style>body{color:red}</style>text");
    expect(result).not.toContain("<style>");
    expect(result).toContain("text");
  });

  it("handles input with only whitespace", () => {
    expect(sanitizeHtml("   ")).toBe("   ");
  });

  it("handles deeply nested tags leaving only text", () => {
    expect(sanitizeHtml("<ul><li><span>item</span></li></ul>")).toBe("item");
  });

  it("strips iframe tags", () => {
    const result = sanitizeHtml('<iframe src="evil.com"></iframe>safe');
    expect(result).not.toContain("iframe");
    expect(result).toContain("safe");
  });

  it("strips self-closing <br /> tag leaving no tag remnants", () => {
    const result = sanitizeHtml("line1<br />line2");
    expect(result).not.toContain("<br");
    expect(result).not.toContain("/>");
    expect(result).toContain("line1");
    expect(result).toContain("line2");
  });

  it("strips self-closing <img /> tag with attributes leaving no tag remnants", () => {
    const result = sanitizeHtml('before<img src="x" alt="y" />after');
    expect(result).not.toContain("<img");
    expect(result).not.toContain("src=");
    expect(result).toContain("before");
    expect(result).toContain("after");
  });
});
