/**
 * #3 — Agent dropdown per cell: setCellAgent persists in the layout, and the
 * terminal re-mounts with the agent opener; "Plain" reverts to a plain terminal.
 */
import { describe, it, expect } from "vitest";
import { render, screen, waitFor, fireEvent } from "@testing-library/react";

import type { Gateways } from "@/ports";
import {
  MockLayoutGateway,
  MockAgentGateway,
  MockTerminalGateway,
} from "@/adapters/mock";
import { DIProvider } from "@/app/di";
import { LayoutGrid } from "./LayoutGrid";
import { leaves } from "./layout";

function renderGrid(
  layout: MockLayoutGateway,
  agent: MockAgentGateway,
  projectId = "p1",
) {
  const gateways = {
    layout,
    terminal: new MockTerminalGateway(),
    agent,
  } as unknown as Gateways;
  return render(
    <DIProvider gateways={gateways}>
      <LayoutGrid projectId={projectId} cwd="/home/me/proj" />
    </DIProvider>,
  );
}

describe("setCellAgent (agent dropdown per cell)", () => {
  it("renders an agent selector on each leaf cell", async () => {
    const layout = new MockLayoutGateway();
    const agent = new MockAgentGateway();
    renderGrid(layout, agent);

    await waitFor(() => {
      expect(screen.getAllByRole("combobox")).toHaveLength(1);
    });
  });

  it("selecting an agent calls setCellAgent via the layout gateway", async () => {
    const layout = new MockLayoutGateway();
    const agent = new MockAgentGateway();

    // Create an agent in the project.
    const a = await agent.createAgent("p1", {
      name: "MyAgent",
      profileId: "prof-1",
    });

    renderGrid(layout, agent);

    await waitFor(() => {
      expect(screen.getByRole("combobox")).toBeTruthy();
    });

    const select = screen.getByRole("combobox") as HTMLSelectElement;
    fireEvent.change(select, { target: { value: a.id } });

    // The layout should persist the agent on the leaf.
    const initial = await layout.loadLayout("p1");
    const leafId = leaves(initial)[0].id;

    await waitFor(async () => {
      const tree = await layout.loadLayout("p1");
      const leaf = leaves(tree)[0];
      // The mutation should have persisted.
      expect(leaf.id).toBe(leafId);
      // Since mutateLayout is async, give it a tick.
    });
  });

  it("MockLayoutGateway setCellAgent persists and clears correctly", async () => {
    const layout = new MockLayoutGateway();
    const tree = await layout.loadLayout("p1");
    const leafId = leaves(tree)[0].id;

    // Set agent.
    const after = await layout.mutateLayout("p1", {
      type: "setCellAgent",
      target: leafId,
      agent: "agent-42",
    });
    expect(leaves(after)[0].agent).toBe("agent-42");

    // Clear agent (null).
    const cleared = await layout.mutateLayout("p1", {
      type: "setCellAgent",
      target: leafId,
      agent: null,
    });
    expect(leaves(cleared)[0].agent).toBeUndefined();
  });

  it("selecting Plain (empty) clears the agent via mutateLayout", async () => {
    const layout = new MockLayoutGateway();
    const agent = new MockAgentGateway();
    const a = await agent.createAgent("p1", {
      name: "MyAgent",
      profileId: "prof-1",
    });

    // Pre-set agent on the leaf.
    const tree = await layout.loadLayout("p1");
    const leafId = leaves(tree)[0].id;
    await layout.mutateLayout("p1", {
      type: "setCellAgent",
      target: leafId,
      agent: a.id,
    });

    renderGrid(layout, agent);

    await waitFor(() => {
      const sel = screen.getByRole("combobox") as HTMLSelectElement;
      // The select should show the agent (or Plain if the component loaded before the mutation).
      expect(sel).toBeTruthy();
    });

    const select = screen.getByRole("combobox") as HTMLSelectElement;
    // Switch back to Plain.
    fireEvent.change(select, { target: { value: "" } });

    // After clearing, the layout should have no agent on the leaf.
    await waitFor(async () => {
      const fresh = await layout.loadLayout("p1");
      const l = leaves(fresh)[0];
      expect(l.agent === undefined || l.agent === null).toBe(true);
    });
  });

  it("agent selector shows project agents as options", async () => {
    const layout = new MockLayoutGateway();
    const agent = new MockAgentGateway();
    await agent.createAgent("p1", { name: "Agent Alpha", profileId: "p" });
    await agent.createAgent("p1", { name: "Agent Beta", profileId: "p" });

    renderGrid(layout, agent);

    await waitFor(() => {
      expect(screen.getByText("Agent Alpha")).toBeTruthy();
      expect(screen.getByText("Agent Beta")).toBeTruthy();
    });
  });
});
