import { describe, expect, mock, test } from "bun:test";
import { screen, waitFor } from "@testing-library/react";
import { createElement } from "react";

import { HighlightBlock } from "../../../../src/web/features/chat/parts/HighlightBlock";
import { renderWithProviders } from "../../test-utils";

describe("HighlightBlock JSON 高亮", () => {
  test("非流式状态渲染 shiki 高亮 HTML", async () => {
    const code = JSON.stringify({ key: "value" }, null, 2);

    const { container } = renderWithProviders(
      createElement(HighlightBlock, { code, isStreaming: false, lang: "json" }),
    );

    expect(screen.getByText("json")).toBeTruthy();

    await waitFor(() => {
      expect(container.querySelector(".code-block-body")).toBeTruthy();
    });
  });

  test("流式状态渲染纯 <pre><code> 无高亮", () => {
    const code = JSON.stringify({ key: "value" }, null, 2);

    const { container } = renderWithProviders(createElement(HighlightBlock, { code, isStreaming: true, lang: "json" }));

    const pre = container.querySelector("pre.code-block");
    expect(pre).toBeTruthy();
    expect(pre!.textContent).toContain("key");
    expect(container.querySelector(".code-block-header")).toBeNull();
  });
});

describe("HighlightBlock 复制按钮", () => {
  test("非流式状态显示复制按钮", () => {
    const code = "const x = 1;";

    renderWithProviders(createElement(HighlightBlock, { code, isStreaming: false, lang: "text" }));

    expect(screen.getByText("text")).toBeTruthy();
    const buttons = screen.getAllByRole("button");
    expect(buttons.length).toBeGreaterThan(0);
  });

  test("复制按钮调用 clipboard.writeText", () => {
    const code = JSON.stringify({ a: 1 }, null, 2);
    const writeTextMock = mock(() => Promise.resolve());
    Object.defineProperty(navigator, "clipboard", {
      value: { writeText: writeTextMock },
      writable: true,
      configurable: true,
    });

    renderWithProviders(createElement(HighlightBlock, { code, isStreaming: false, lang: "json" }));

    const button = screen.getByRole("button");
    button.click();

    expect(writeTextMock).toHaveBeenCalledWith(code);
  });
});

describe("HighlightBlock 纯文本", () => {
  test("lang=text 时头部显示 text", () => {
    renderWithProviders(createElement(HighlightBlock, { code: "hello world", isStreaming: false, lang: "text" }));

    expect(screen.getByText("text")).toBeTruthy();
  });
});

describe("HighlightBlock 边界情况", () => {
  test("code 为空时渲染空代码块不触发异步高亮", () => {
    const { container } = renderWithProviders(
      createElement(HighlightBlock, { code: "", isStreaming: false, lang: "json" }),
    );

    expect(container.querySelector(".code-block")).toBeTruthy();
    expect(container.querySelector("code")).toBeTruthy();
    expect(container.querySelector("code")!.textContent).toBe("");
  });

  test("流式切换到非流式后触发高亮", async () => {
    const code = JSON.stringify({ x: 1 }, null, 2);
    const { container, rerender } = renderWithProviders(
      createElement(HighlightBlock, { code, isStreaming: true, lang: "json" }),
    );

    expect(container.querySelector("pre.code-block")).toBeTruthy();

    rerender(createElement(HighlightBlock, { code, isStreaming: false, lang: "json" }));

    await waitFor(() => {
      expect(container.querySelector(".code-block-body")).toBeTruthy();
    });
  });
});
