/**
 * #22 — view anchoring/docking in `ProjectsView`. A view opened from the menu
 * starts floating (modal window); its header controls move it into the in-flow
 * left/right {@link DockRegion} and back, and the one-slot-per-view invariant
 * holds (docking a floating view removes the modal window).
 */
import { describe, it, expect } from "vitest";
import { render, screen, within, waitFor, fireEvent } from "@testing-library/react";

import {
  MockAgentGateway,
  MockGitGateway,
  MockProfileGateway,
  MockProjectGateway,
  MockSystemGateway,
  MockTemplateGateway,
  MockWindowGateway,
  MockWorkStateGateway,
} from "@/adapters/mock";
import type { Gateways } from "@/ports";
import { DIProvider } from "@/app/di";
import { ProjectsView } from "./ProjectsView";

async function renderWithProject() {
  const project = new MockProjectGateway();
  await project.createProject("alpha", "/p/a");
  const agentGateway = new MockAgentGateway();
  const gateways = {
    system: new MockSystemGateway(),
    project,
    agent: agentGateway,
    profile: new MockProfileGateway(),
    template: new MockTemplateGateway(agentGateway),
    git: new MockGitGateway(),
    workState: new MockWorkStateGateway(),
    window: new MockWindowGateway(),
  } as unknown as Gateways;
  render(
    <DIProvider gateways={gateways}>
      <ProjectsView />
    </DIProvider>,
  );
  // Open the seeded project so panels have an active project to render for.
  fireEvent.click(await screen.findByRole("button", { name: "Open" }));
  await waitFor(() =>
    expect(within(screen.getByRole("tablist")).getAllByRole("tab")).toHaveLength(1),
  );
}

/**
 * Opens a panel floating via the single « Panneaux » menu (#26): menu → panel
 * entry (opens its placement submenu) → « Flottant ». `panelTitle` is the
 * panel's human title ("Git", "Agents", …).
 */
function openPanelFloating(panelTitle: string) {
  fireEvent.click(screen.getByRole("button", { name: "Panneaux" }));
  fireEvent.click(screen.getByRole("button", { name: panelTitle }));
  fireEvent.click(screen.getByRole("button", { name: "Flottant" }));
}

describe("ProjectsView view docking (#22)", () => {
  it("opens a view floating, then docks it left as an in-flow column", async () => {
    await renderWithProject();

    // View → Git opens a modal floating window (historical behaviour).
    openPanelFloating("Git");
    const dialog = await screen.findByRole("dialog", { name: "Git" });
    expect(dialog).toBeTruthy();

    // Dock it to the left via the header control.
    fireEvent.click(within(dialog).getByRole("button", { name: "Ancré à gauche — Git" }));

    // The modal window is gone; the Git view now lives in the left dock column.
    await waitFor(() =>
      expect(screen.queryByRole("dialog", { name: "Git" })).toBeNull(),
    );
    const leftDock = screen.getByRole("complementary", { name: "left dock" });
    expect(within(leftDock).getByLabelText("Git panel")).toBeTruthy();
    // The main surface is still present beside the dock (in-flow, not overlay).
    expect(screen.getByRole("main")).toBeTruthy();
  });

  it("keeps one slot per view: docking right moves it off the left dock", async () => {
    await renderWithProject();

    openPanelFloating("Git");
    const dialog = await screen.findByRole("dialog", { name: "Git" });
    fireEvent.click(within(dialog).getByRole("button", { name: "Ancré à gauche — Git" }));

    const leftDock = await screen.findByRole("complementary", { name: "left dock" });
    const leftHeader = within(leftDock).getByLabelText("Git panel");
    // Move it to the right dock from the docked header control.
    fireEvent.click(
      within(leftHeader).getByRole("button", { name: "Ancré à droite — Git" }),
    );

    await waitFor(() =>
      expect(screen.queryByRole("complementary", { name: "left dock" })).toBeNull(),
    );
    const rightDock = screen.getByRole("complementary", { name: "right dock" });
    expect(within(rightDock).getByLabelText("Git panel")).toBeTruthy();
  });

  it("docks two different views side by side (left + right)", async () => {
    await renderWithProject();

    // Dock Git left.
    openPanelFloating("Git");
    fireEvent.click(
      within(await screen.findByRole("dialog", { name: "Git" })).getByRole(
        "button",
        { name: "Ancré à gauche — Git" },
      ),
    );
    // Dock Agents right.
    openPanelFloating("Agents");
    fireEvent.click(
      within(await screen.findByRole("dialog", { name: "Agents" })).getByRole(
        "button",
        { name: "Ancré à droite — Agents" },
      ),
    );

    const leftDock = await screen.findByRole("complementary", { name: "left dock" });
    const rightDock = await screen.findByRole("complementary", { name: "right dock" });
    expect(within(leftDock).getByLabelText("Git panel")).toBeTruthy();
    expect(within(rightDock).getByLabelText("Agents panel")).toBeTruthy();
  });
});
