import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { micromark } from "micromark";
import { afterEach, describe, expect, it, vi } from "vitest";

import { LabContent } from "~/components/labs/LabContent";
import { getLabDocument } from "~/lib/labs";

describe("LabContent", () => {
  afterEach(() => {
    vi.restoreAllMocks();
  });

  function mockRuntimeConfig(config?: Record<string, unknown>) {
    return vi.spyOn(globalThis, "fetch").mockImplementation(async () => {
      return new Response(
        JSON.stringify(
          config ?? {
            lab1NetronUrl: "http://127.0.0.1:8338",
            lab2OllamaModels: [
              {
                label: "Gemma 4 E2B Q4",
                value: "batiai/gemma4-e2b:q4",
              },
            ],
            lab2OllamaUrl: "http://127.0.0.1:11434",
            lab3TerminalUrl: "http://127.0.0.1:7681/wetty",
          },
        ),
        { status: 200 },
      );
    });
  }

  it("renders the Lab 1 widget tokens into interactive components", async () => {
    mockRuntimeConfig();

    render(
      <LabContent
        className="lab-content"
        html={[
          "<div data-lab1-netron-panel></div>",
          "<div data-tokenizer-playground></div>",
          "<div data-lab1-confidence></div>",
        ].join("")}
      />,
    );

    await waitFor(() => {
      expect(
        screen.getByRole("link", { name: "Open Netron" }),
      ).toBeInTheDocument();
    });
    expect(screen.getByText("Tokenizer Playground")).toBeInTheDocument();
    expect(
      screen.getByText("Visualize token confidence locally"),
    ).toBeInTheDocument();
  });

  it("filters harness branches from a single Objective 2 selector", async () => {
    mockRuntimeConfig();

    render(
      <LabContent
        className="lab-content"
        html={[
          '<div class="lab-harness-chooser">',
          '<button type="button" class="lab-harness-card" data-harness-choice="opencode">OpenCode</button>',
          '<button type="button" class="lab-harness-card" data-harness-choice="kilocode">Kilo Code</button>',
          '<button type="button" class="lab-harness-card" data-harness-choice="droid">Factory Droid</button>',
          "</div>",
          '<section data-harness-branch="opencode"><h3>OpenCode Install</h3></section>',
          '<section data-harness-branch="kilocode"><h3>Kilo Code Install</h3></section>',
          '<section data-harness-branch="droid"><h3>Factory Droid Install</h3></section>',
          '<section data-harness-branch="opencode"><h3>OpenCode Config</h3></section>',
          '<section data-harness-branch="kilocode"><h3>Kilo Code Config</h3></section>',
        ].join("")}
      />,
    );

    const openCodeInstall = screen
      .getByText("OpenCode Install")
      .closest("section");
    const kiloCodeInstall = screen
      .getByText("Kilo Code Install")
      .closest("section");
    const droidInstall = screen
      .getByText("Factory Droid Install")
      .closest("section");
    const kiloCodeConfig = screen
      .getByText("Kilo Code Config")
      .closest("section");

    await waitFor(() => {
      expect(openCodeInstall?.hidden).toBe(true);
      expect(kiloCodeInstall?.hidden).toBe(true);
      expect(droidInstall?.hidden).toBe(true);
      expect(kiloCodeConfig?.hidden).toBe(true);
    });

    fireEvent.click(screen.getByRole("button", { name: "Kilo Code" }));

    expect(screen.getByRole("button", { name: "Kilo Code" })).toHaveAttribute(
      "aria-pressed",
      "true",
    );
    expect(openCodeInstall?.hidden).toBe(true);
    expect(kiloCodeInstall?.hidden).toBe(false);
    expect(droidInstall?.hidden).toBe(true);
    expect(kiloCodeConfig?.hidden).toBe(false);

    fireEvent.click(screen.getByRole("button", { name: "Kilo Code" }));

    expect(screen.getByRole("button", { name: "Kilo Code" })).toHaveAttribute(
      "aria-pressed",
      "false",
    );
    expect(openCodeInstall?.hidden).toBe(true);
    expect(kiloCodeInstall?.hidden).toBe(true);
    expect(droidInstall?.hidden).toBe(true);
  });

  it("renders service URL tokens in prose as clickable links", async () => {
    mockRuntimeConfig();

    render(
      <LabContent
        className="lab-content"
        html="<p>Open WebUI lives at {{service-url:open-webui}}.</p>"
      />,
    );

    const link = await screen.findByRole("link", {
      name: "Open WebUI on port 8080",
    });

    expect(link).toHaveAttribute("href", "http://localhost:8080/");
    expect(link).toHaveAttribute("title", "http://localhost:8080/");
    expect(link).toHaveClass("lab-service-pill");
  });

  it("keeps rendered service URL links after opening an image zoom modal", async () => {
    mockRuntimeConfig();

    const { container } = render(
      <LabContent
        className="lab-content"
        html={[
          "<p>Embedding Atlas lives at {{service-url:embedding-atlas}}.</p>",
          '<p><img src="/diagram.png" alt="Embedding diagram" /></p>',
        ].join("")}
      />,
    );

    const link = await screen.findByRole("link", {
      name: "Embedding Atlas on port 5055",
    });

    fireEvent.click(container.querySelector("img") as HTMLImageElement);

    await waitFor(() => {
      expect(screen.getAllByAltText("Embedding diagram")).toHaveLength(2);
    });
    expect(link).toHaveAttribute("href", "http://localhost:5055/");
    expect(
      screen.queryByText("{{service-url:embedding-atlas}}"),
    ).not.toBeInTheDocument();
  });

  it("renders inline service URL tokens inside code as plain text", async () => {
    mockRuntimeConfig();

    render(
      <LabContent
        className="lab-content"
        html="<p>Use <code>{{service-url:open-webui:/api}}</code> as the base URL.</p>"
      />,
    );

    expect(
      await screen.findByText("http://localhost:8080/api"),
    ).toBeInTheDocument();
    expect(
      screen.queryByRole("link", { name: "http://localhost:8080/api" }),
    ).not.toBeInTheDocument();
  });

  it("renders fenced service URL tokens as plain text that stays copyable", async () => {
    mockRuntimeConfig();

    render(
      <LabContent
        className="lab-content"
        html="<pre><code>{{service-url:open-webui:/api}}</code></pre>"
      />,
    );

    const code = await screen.findByText("http://localhost:8080/api");
    expect(code.closest("pre")).not.toBeNull();
    expect(
      screen.queryByRole("link", { name: "http://localhost:8080/api" }),
    ).not.toBeInTheDocument();
  });

  it("renders SSH address tokens as plain host and port text", async () => {
    mockRuntimeConfig();

    render(
      <LabContent
        className="lab-content"
        html="<p>Fallback SSH access: {{service-address:ssh}}</p>"
      />,
    );

    expect(
      await screen.findByText("Fallback SSH access: localhost:22", {
        selector: "p",
      }),
    ).toBeInTheDocument();
    expect(
      screen.queryByRole("link", { name: "localhost:22" }),
    ).not.toBeInTheDocument();
  });

  it("renders the real Lab 5 service references with runtime URLs", async () => {
    mockRuntimeConfig({
      services: {
        "open-webui": "https://lab.example/openwebui",
      },
    });

    const lab = getLabDocument("lab-5-api-and-harnesses");
    expect(lab).not.toBeNull();

    render(
      <LabContent
        className="lab-content"
        html={micromark(lab?.content ?? "", { allowDangerousHtml: true })}
      />,
    );

    expect(
      await screen.findByRole("link", { name: "Open WebUI" }),
    ).toHaveAttribute("href", "https://lab.example/openwebui");
    expect(screen.getByRole("link", { name: "Open WebUI" })).toHaveClass(
      "lab-service-pill",
    );
    expect(screen.getByRole("link", { name: "Open WebUI" })).toHaveAttribute(
      "title",
      "https://lab.example/openwebui",
    );
    const apiMatches = await screen.findAllByText(
      "https://lab.example/openwebui/api",
    );
    expect(apiMatches.some((node) => node.tagName === "CODE")).toBe(true);
    expect(
      screen.queryByRole("link", { name: "https://lab.example/openwebui/api" }),
    ).not.toBeInTheDocument();
  });
});
