/**
 * #23/#47 — the panel-only entry. `parseViewWindowParams` validates the
 * `?panel=` query (no project id anymore), and `ViewWindow` follows the main
 * window's focused project: it shows an "open a project" shell while no project
 * is focused and mounts the requested view once one is, without ever opening a
 * project itself.
 */
import { describe, it, expect } from "vitest";
import { render, screen, waitFor, act } from "@testing-library/react";

import { DIProvider } from "@/app/di";
import {
  MockAgentGateway,
  MockFocusedProjectGateway,
  MockProjectGateway,
  MockSystemGateway,
  MockTicketGateway,
} from "@/adapters/mock";
import type { Gateways } from "@/ports";
import { ViewWindow, parseViewWindowParams } from "./ViewWindow";

describe("parseViewWindowParams (#47)", () => {
  it("parses a valid panel-only query (ignores any legacy project param)", () => {
    expect(parseViewWindowParams("?panel=tickets")).toEqual({
      panel: "tickets",
    });
    // A restored legacy URL that still carries `project` parses to panel only.
    expect(parseViewWindowParams("?panel=tickets&project=p-1")).toEqual({
      panel: "tickets",
    });
  });

  it("rejects a missing panel or the non-detachable projects panel", () => {
    expect(parseViewWindowParams("?project=p-1")).toBeNull();
    expect(parseViewWindowParams("?panel=projects")).toBeNull();
    expect(parseViewWindowParams("?panel=bogus")).toBeNull();
    expect(parseViewWindowParams("")).toBeNull();
  });
});

describe("ViewWindow (#47)", () => {
  it("shows the 'open a project' shell when no project is focused", async () => {
    const system = new MockSystemGateway();
    const gateways = {
      system,
      project: new MockProjectGateway(),
      agent: new MockAgentGateway(),
      ticket: new MockTicketGateway(system),
      focusedProject: new MockFocusedProjectGateway(),
    } as unknown as Gateways;

    render(
      <DIProvider gateways={gateways}>
        <ViewWindow panel="tickets" />
      </DIProvider>,
    );

    // The panel title chrome is present, but no project-scoped view mounts…
    expect(screen.getByRole("heading", { name: "Tickets" })).toBeTruthy();
    await waitFor(() =>
      expect(screen.getByText(/Ouvrez un projet/i)).toBeTruthy(),
    );
    expect(screen.queryByLabelText("search tickets")).toBeNull();
  });

  it("mounts the view for the focused project and follows focus changes", async () => {
    const system = new MockSystemGateway();
    const project = new MockProjectGateway();
    const created = await project.createProject("alpha", "/p/a");
    const focusedProject = new MockFocusedProjectGateway();
    const gateways = {
      system,
      project,
      agent: new MockAgentGateway(),
      ticket: new MockTicketGateway(system),
      focusedProject,
    } as unknown as Gateways;

    render(
      <DIProvider gateways={gateways}>
        <ViewWindow panel="tickets" />
      </DIProvider>,
    );

    // No focus yet → shell.
    await waitFor(() =>
      expect(screen.getByText(/Ouvrez un projet/i)).toBeTruthy(),
    );

    // The main window publishes a focused project → the window follows it.
    await act(async () => {
      await focusedProject.setFocusedProject({
        id: created.id,
        name: "alpha",
        root: "/p/a",
      });
    });

    await waitFor(() => expect(screen.getByText("· alpha")).toBeTruthy());
    await waitFor(() =>
      expect(screen.getByLabelText("search tickets")).toBeTruthy(),
    );

    // Focus cleared (project closed) → back to the shell, view unmounts.
    await act(async () => {
      await focusedProject.setFocusedProject(null);
    });
    await waitFor(() =>
      expect(screen.getByText(/Ouvrez un projet/i)).toBeTruthy(),
    );
    expect(screen.queryByLabelText("search tickets")).toBeNull();
  });

  it("reads the current focus at mount (restored window with a live focus)", async () => {
    const system = new MockSystemGateway();
    const project = new MockProjectGateway();
    const created = await project.createProject("beta", "/p/b");
    const focusedProject = new MockFocusedProjectGateway();
    // Focus already set before the window mounts (main window opened first).
    await focusedProject.setFocusedProject({
      id: created.id,
      name: "beta",
      root: "/p/b",
    });
    const gateways = {
      system,
      project,
      agent: new MockAgentGateway(),
      ticket: new MockTicketGateway(system),
      focusedProject,
    } as unknown as Gateways;

    render(
      <DIProvider gateways={gateways}>
        <ViewWindow panel="tickets" />
      </DIProvider>,
    );

    await waitFor(() => expect(screen.getByText("· beta")).toBeTruthy());
    await waitFor(() =>
      expect(screen.getByLabelText("search tickets")).toBeTruthy(),
    );
  });
});
