import { afterEach, describe, expect, it, jest } from "@jest/globals";
import { flushPromises, mount } from "@vue/test-utils";

import MermaidCard from "../../../frontend/src/components/MermaidCard.vue";
import mermaid from "mermaid";

describe("MermaidCard", () => {
  afterEach(() => {
    jest.restoreAllMocks();
    document.body.style.overflow = "";
  });

  it("renders diagrams and handles the fullscreen overlay lifecycle", async () => {
    const initSpy = jest.spyOn(mermaid, "initialize");
    const renderSpy = jest.spyOn(mermaid, "render").mockResolvedValue({
      svg: "<svg><g>ok</g></svg>",
    });

    const wrapper = mount(MermaidCard, {
      props: {
        title: "Network",
        description: "Topology",
        diagram: "graph TD;A-->B;",
        cardId: "network-card",
      },
    });

    await flushPromises();

    expect(initSpy).toHaveBeenCalledTimes(1);
    expect(renderSpy).toHaveBeenCalled();
    expect(wrapper.html()).toContain("<svg");

    await wrapper.find(".diagram").trigger("click");
    expect(wrapper.find(".overlay").exists()).toBe(true);
    expect(document.body.style.overflow).toBe("hidden");

    window.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" }));
    await flushPromises();
    expect(wrapper.find(".overlay").exists()).toBe(false);
    expect(document.body.style.overflow).toBe("");

    await wrapper.unmount();
  });

  it("renders Mermaid errors and re-renders when the diagram changes", async () => {
    const renderSpy = jest
      .spyOn(mermaid, "render")
      .mockRejectedValueOnce(new Error("invalid diagram"))
      .mockResolvedValueOnce({ svg: "<svg><text>recovered</text></svg>" });

    const wrapper = mount(MermaidCard, {
      props: {
        title: "Pipeline",
        description: "Initial",
        diagram: "graph TD;BROKEN",
      },
    });

    await flushPromises();
    expect(wrapper.text()).toContain("Mermaid render error");

    await wrapper.setProps({ diagram: "graph TD;X-->Y;" });
    await flushPromises();

    expect(renderSpy).toHaveBeenCalledTimes(2);
    expect(wrapper.html()).toContain("<svg");

    await wrapper.unmount();
    expect(document.body.style.overflow).toBe("");
  });

  it("no-ops rendering when no diagram is provided", async () => {
    const renderSpy = jest.spyOn(mermaid, "render");
    const wrapper = mount(MermaidCard, {
      props: {
        title: "Empty",
        description: "No diagram yet",
        diagram: "",
      },
    });

    await flushPromises();
    expect(renderSpy).not.toHaveBeenCalled();

    await wrapper.unmount();
  });
});
