// @vitest-environment jsdom

import { act } from "react";
import { createRoot } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { MemoryRouter } from "@/lib/router";
import { IconRail } from "./IconRail";

// The real @/lib/router Link wrapper calls useCompany(), which throws
// outside a CompanyProvider. The IconRail doesn't depend on the company
// context for building URLs (it receives companyPrefix as a prop), so we
// stub useCompany() to return a minimal value so Link can render in tests.
vi.mock("@/context/CompanyContext", () => ({
  useCompany: () => ({
    companies: [],
    selectedCompanyId: null,
    selectedCompany: null,
    selectionSource: "bootstrap" as const,
    loading: false,
    error: null,
    setSelectedCompanyId: () => {},
    reloadCompanies: async () => {},
    createCompany: async () => {
      throw new Error("not implemented in test stub");
    },
  }),
}));

// Tell React this environment uses act() for event flushing.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;

describe("IconRail", () => {
  let container: HTMLDivElement;
  let root: ReturnType<typeof createRoot> | null = null;

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

  afterEach(() => {
    if (root) {
      act(() => {
        root!.unmount();
      });
      root = null;
    }
    if (container.parentNode) {
      container.remove();
    }
  });

  function renderRail(initialPath: string) {
    root = createRoot(container);
    act(() => {
      root!.render(
        <MemoryRouter initialEntries={[initialPath]}>
          <IconRail companyPrefix="NEX" />
        </MemoryRouter>,
      );
    });
    return {
      getNav: () => container.querySelector("nav[aria-label='Primary']") as HTMLElement,
      getLinks: () =>
        Array.from(container.querySelectorAll("nav[aria-label='Primary'] a")) as HTMLAnchorElement[],
      getLinkByLabel: (label: string) =>
        container.querySelector(`nav[aria-label='Primary'] a[aria-label='${label}']`) as HTMLAnchorElement | null,
    };
  }

  it("renders a Primary nav with the four destination links", () => {
    const { getNav, getLinks } = renderRail("/NEX/assistant");
    expect(getNav()).not.toBeNull();
    const links = getLinks();
    // The rail also renders a "Nexus home" link for the mark at the top;
    // we filter to just the four destinations below.
    const labels = links
      .map((a) => a.getAttribute("aria-label"))
      .filter((label) => label !== "Nexus home");
    expect(labels).toEqual(["Assistant", "Studio", "Projects", "Settings"]);
  });

  it("builds company-prefixed URLs for the first three destinations", () => {
    const { getLinkByLabel } = renderRail("/NEX/assistant");
    expect(getLinkByLabel("Assistant")?.getAttribute("href")).toBe("/NEX/assistant");
    expect(getLinkByLabel("Studio")?.getAttribute("href")).toBe("/NEX/content-studio");
    expect(getLinkByLabel("Projects")?.getAttribute("href")).toBe("/NEX/projects");
  });

  it("points Settings at the global /instance/settings/general route", () => {
    const { getLinkByLabel } = renderRail("/NEX/assistant");
    expect(getLinkByLabel("Settings")?.getAttribute("href")).toBe("/instance/settings/general");
  });

  it("marks the Assistant link as current on /NEX/assistant", () => {
    const { getLinkByLabel } = renderRail("/NEX/assistant");
    expect(getLinkByLabel("Assistant")?.getAttribute("aria-current")).toBe("page");
    expect(getLinkByLabel("Projects")?.getAttribute("aria-current")).toBeNull();
  });

  it("marks the Projects link as current on /NEX/issues", () => {
    const { getLinkByLabel } = renderRail("/NEX/issues");
    expect(getLinkByLabel("Projects")?.getAttribute("aria-current")).toBe("page");
    expect(getLinkByLabel("Assistant")?.getAttribute("aria-current")).toBeNull();
  });

  it("marks the Studio link as current on /NEX/convert (Convert is folded into Studio)", () => {
    const { getLinkByLabel } = renderRail("/NEX/convert");
    expect(getLinkByLabel("Studio")?.getAttribute("aria-current")).toBe("page");
  });

  it("marks the Settings link as current on /instance/settings/general", () => {
    const { getLinkByLabel } = renderRail("/instance/settings/general");
    expect(getLinkByLabel("Settings")?.getAttribute("aria-current")).toBe("page");
  });
});
