import { render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { EditorView } from "@codemirror/view";

import { DiffView } from "../src/client/DiffView.js";

function leftPaneSelection(): { from: number; to: number } | null {
  const pane = document.querySelector(".diff-host .cm-editor");
  if (pane === null) {
    return null;
  }
  const view = EditorView.findFromDOM(pane as HTMLElement);
  if (view === null) {
    return null;
  }
  const { from, to } = view.state.selection.main;
  return { from, to };
}

describe("DiffView", () => {
  it("keeps Markdown and raw HTML as inert editor text", () => {
    render(
      <DiffView
        before={'# title\n<img src="https://example.com/private.png" onerror="alert(1)">'}
        after={'# title\n<script>alert("x")</script>'}
        beforeLabel="清洗前"
        afterLabel="清洗后"
      />,
    );

    expect(screen.getByRole("region", { name: "清洗前与清洗后对比" })).toBeInTheDocument();
    expect(document.querySelector("img")).toBeNull();
    expect(document.querySelector("script")).toBeNull();
  });

  it("keeps long unchanged sections available in the full document view", () => {
    const before = Array.from({ length: 30 }, (_, index) => `line ${index + 1}`);
    const after = [...before];
    after[14] = "changed line 15";

    render(
      <DiffView
        before={before.join("\n")}
        after={after.join("\n")}
        beforeLabel="清洗前"
        afterLabel="清洗后"
      />,
    );

    expect(document.querySelector(".cm-collapsedLines")).toBeNull();
  });

  it("re-applies the focus selection after the compared texts change", () => {
    const longText = (mark: string) =>
      Array.from({ length: 30 }, (_, index) => (index === 14 ? mark : `line ${index + 1}`)).join("\n");

    const { rerender } = render(
      <DiffView before={longText("old")} after={longText("new")} beforeLabel="清洗前" afterLabel="清洗后" />,
    );

    // 模拟点击跨组件修改项：focusRange 先落在旧文本上，stage 文本随后到达。
    rerender(
      <DiffView
        before={longText("old")}
        after={longText("new")}
        beforeLabel="组件 1 执行前"
        afterLabel="组件 1 执行后"
        focusRange={{ start: 58, end: 61 }}
      />,
    );
    rerender(
      <DiffView
        before={longText("stage before")}
        after={longText("stage after")}
        beforeLabel="组件 2 执行前"
        afterLabel="组件 2 执行后"
        focusRange={{ start: 58, end: 71 }}
      />,
    );

    // 最终视图必须是组件 2 的文本，且选区重新落在新文本的目标范围上。
    expect(screen.getByRole("region", { name: "组件 2 执行前与组件 2 执行后对比" })).toBeInTheDocument();
    expect(leftPaneSelection()).toEqual({ from: 58, to: 71 });
  });

  it("applies the focus selection when it arrives with the initial texts", () => {
    render(
      <DiffView
        before={"a\nb"}
        after={"a\nc"}
        beforeLabel="清洗前"
        afterLabel="清洗后"
        focusRange={{ start: 0, end: 1 }}
      />,
    );

    expect(leftPaneSelection()).toEqual({ from: 0, to: 1 });
  });
});
