// @vitest-environment jsdom

import { act } from "react";
import { createRoot } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
import { ThemeProvider } from "../context/ThemeContext";
import { ChatMarkdownMessage } from "./ChatMarkdownMessage";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;

// Mock clipboard API (not available in jsdom by default)
const writeText = vi.fn().mockResolvedValue(undefined);
Object.defineProperty(navigator, "clipboard", {
  value: { writeText },
  writable: true,
  configurable: true,
});

describe("ChatMarkdownMessage", () => {
  let container: HTMLDivElement;

  beforeEach(() => {
    container = document.createElement("div");
    document.body.appendChild(container);
    writeText.mockClear();
  });

  afterEach(() => {
    container.remove();
  });

  it("renders markdown headings", () => {
    act(() => {
      createRoot(container).render(
        <ThemeProvider>
          <ChatMarkdownMessage content="# Hello World" />
        </ThemeProvider>,
      );
    });
    const heading = container.querySelector("h1");
    expect(heading).not.toBeNull();
    expect(heading?.textContent).toBe("Hello World");
  });

  it("renders markdown bold and italic", () => {
    act(() => {
      createRoot(container).render(
        <ThemeProvider>
          <ChatMarkdownMessage content="**bold** and _italic_" />
        </ThemeProvider>,
      );
    });
    expect(container.querySelector("strong")).not.toBeNull();
    expect(container.querySelector("em")).not.toBeNull();
  });

  it("renders markdown lists", () => {
    act(() => {
      createRoot(container).render(
        <ThemeProvider>
          <ChatMarkdownMessage content={"- item one\n- item two"} />
        </ThemeProvider>,
      );
    });
    expect(container.querySelector("ul")).not.toBeNull();
    const items = container.querySelectorAll("li");
    expect(items.length).toBe(2);
  });

  it("renders markdown links", () => {
    act(() => {
      createRoot(container).render(
        <ThemeProvider>
          <ChatMarkdownMessage content="[Click here](https://example.com)" />
        </ThemeProvider>,
      );
    });
    const link = container.querySelector("a");
    expect(link).not.toBeNull();
    expect(link?.getAttribute("href")).toBe("https://example.com");
  });

  it("renders markdown tables (GFM)", () => {
    const tableContent = "| A | B |\n|---|---|\n| 1 | 2 |";
    act(() => {
      createRoot(container).render(
        <ThemeProvider>
          <ChatMarkdownMessage content={tableContent} />
        </ThemeProvider>,
      );
    });
    expect(container.querySelector("table")).not.toBeNull();
    expect(container.querySelector("th")).not.toBeNull();
  });

  it("renders code block with copy button", () => {
    act(() => {
      createRoot(container).render(
        <ThemeProvider>
          <ChatMarkdownMessage content={"```typescript\nconst x = 1;\n```"} />
        </ThemeProvider>,
      );
    });
    const copyBtn = container.querySelector('[aria-label="Copy code"]');
    expect(copyBtn).not.toBeNull();
  });

  it("renders code block with language label when language is specified", () => {
    act(() => {
      createRoot(container).render(
        <ThemeProvider>
          <ChatMarkdownMessage content={"```typescript\nconst x = 1;\n```"} />
        </ThemeProvider>,
      );
    });
    expect(container.textContent).toContain("typescript");
  });

  it("clicking copy button calls clipboard.writeText with code content", async () => {
    act(() => {
      createRoot(container).render(
        <ThemeProvider>
          <ChatMarkdownMessage content={"```\nconst y = 2;\n```"} />
        </ThemeProvider>,
      );
    });
    const copyBtn = container.querySelector('[aria-label="Copy code"]') as HTMLButtonElement | null;
    expect(copyBtn).not.toBeNull();
    await act(async () => {
      copyBtn?.click();
    });
    expect(writeText).toHaveBeenCalledTimes(1);
    expect(writeText).toHaveBeenCalledWith(expect.stringContaining("const y = 2;"));
  });

  it("inline code renders without copy button", () => {
    act(() => {
      createRoot(container).render(
        <ThemeProvider>
          <ChatMarkdownMessage content="Here is `inline code` text" />
        </ThemeProvider>,
      );
    });
    const copyBtn = container.querySelector('[aria-label="Copy code"]');
    expect(copyBtn).toBeNull();
    expect(container.querySelector("code")).not.toBeNull();
  });

  it("renders inline images with img tag", () => {
    act(() => {
      createRoot(container).render(
        <ThemeProvider>
          <ChatMarkdownMessage content="![alt text](https://example.com/img.png)" />
        </ThemeProvider>,
      );
    });
    const img = container.querySelector("img");
    expect(img).not.toBeNull();
    expect(img?.getAttribute("src")).toBe("https://example.com/img.png");
    expect(img?.getAttribute("alt")).toBe("alt text");
  });
});
