import { describe, it, expect, vi } from "vitest";
import { runHtmlEntity } from "./run";
import type { ToolContext } from "../../core/plugins/plugin-types";

describe("HTML Entity Encoder/Decoder", () => {
  const mockContext: ToolContext = {
    signal: new AbortController().signal,
    reportProgress: vi.fn(),
    logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
  };

  it("should encode basic HTML special characters", async () => {
    const result = await runHtmlEntity(
      { text: '<div class="test">Hello & World</div>' },
      { mode: "encode" },
      mockContext
    );
    expect(result.type).toBe("text");
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toBe("&lt;div class=&quot;test&quot;&gt;Hello &amp; World&lt;/div&gt;");
  });

  it("should decode basic HTML entities", async () => {
    const result = await runHtmlEntity(
      { text: "&lt;div&gt;Hello &amp; World&lt;/div&gt;" },
      { mode: "decode" },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toBe("<div>Hello & World</div>");
  });

  it("should encode special symbols", async () => {
    const result = await runHtmlEntity(
      { text: "Price: 10€ © 2024" },
      { mode: "encode" },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toContain("&euro;");
    expect(value).toContain("&copy;");
  });

  it("should decode special symbol entities", async () => {
    const result = await runHtmlEntity(
      { text: "&copy; 2024 &mdash; All rights reserved" },
      { mode: "decode" },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toContain("©");
    expect(value).toContain("—");
  });

  it("should decode numeric character references (decimal)", async () => {
    const result = await runHtmlEntity(
      { text: "&#65;&#66;&#67;" },
      { mode: "decode" },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toBe("ABC");
  });

  it("should decode numeric character references (hex)", async () => {
    const result = await runHtmlEntity(
      { text: "&#x41;&#x42;&#x43;" },
      { mode: "decode" },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toBe("ABC");
  });

  it("should encode single quotes", async () => {
    const result = await runHtmlEntity(
      { text: "it's a test" },
      { mode: "encode" },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toContain("&#39;");
  });

  it("should return empty string for empty input", async () => {
    const result = await runHtmlEntity(
      { text: "" },
      { mode: "encode" },
      mockContext
    );
    const value = (result as { type: "text"; value: string }).value;
    expect(value).toBe("");
  });

  it("should be reversible: encode then decode gives original", async () => {
    const original = '<p>Hello & "World"</p>';
    const encoded = await runHtmlEntity(
      { text: original },
      { mode: "encode" },
      mockContext
    );
    const decoded = await runHtmlEntity(
      { text: (encoded as { type: "text"; value: string }).value },
      { mode: "decode" },
      mockContext
    );
    expect((decoded as { type: "text"; value: string }).value).toBe(original);
  });
});
