import { screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { renderWithProviders } from "../test/renderWithProviders";
import WorkspaceSelector from "./WorkspaceSelector";

function makeWorkspace(name: string, overrides: Record<string, unknown> = {}) {
  return {
    id: `ws-${name}`,
    name,
    slug: name,
    path: `/workspaces/${name}`,
    runtime_backend: "container",
    container_name: `codex-${name}`,
    status: "active",
    provision_state: "ready",
    provision_error: "",
    last_provisioned_at: "",
    container_state: "running",
    ...overrides,
  };
}

describe("WorkspaceSelector", () => {
  it("shows a loading label while workspaces are being resolved", () => {
    renderWithProviders(
      <WorkspaceSelector value="" workspaces={[]} loading onChange={vi.fn()} />,
      { locale: "en" },
    );

    expect(screen.getByRole("button", { name: /loading workspaces/i })).toBeInTheDocument();
  });

  it("lets the user switch to another existing workspace", async () => {
    const onChange = vi.fn();
    const user = userEvent.setup();

    renderWithProviders(
      <WorkspaceSelector
        value="alpha"
        workspaces={[makeWorkspace("alpha"), makeWorkspace("beta")]}
        onChange={onChange}
      />,
      { locale: "en" },
    );

    await user.click(await screen.findByRole("button", { name: /alpha/i }));

    const betaOption = (await screen.findByText("beta")).closest("button");
    if (!betaOption) {
      throw new Error("beta workspace option not found");
    }

    await user.click(betaOption);

    expect(onChange).toHaveBeenCalledWith("beta");
  });

  it("updates the trigger label when the active workspace prop changes", async () => {
    const { rerender } = renderWithProviders(
      <WorkspaceSelector
        value="alpha"
        workspaces={[makeWorkspace("alpha"), makeWorkspace("beta")]}
        onChange={vi.fn()}
      />,
      { locale: "en" },
    );

    expect(await screen.findByRole("button", { name: /alpha/i })).toBeInTheDocument();

    rerender(
      <WorkspaceSelector
        value="beta"
        workspaces={[makeWorkspace("alpha"), makeWorkspace("beta")]}
        onChange={vi.fn()}
      />,
    );

    expect(await screen.findByRole("button", { name: /beta/i })).toBeInTheDocument();
  });

  it("opens a labeled dialog, focuses the active project, and restores focus on escape", async () => {
    const user = userEvent.setup();

    renderWithProviders(
      <WorkspaceSelector
        value="alpha"
        workspaces={[makeWorkspace("alpha"), makeWorkspace("beta")]}
        onChange={vi.fn()}
      />,
      { locale: "en" },
    );

    const trigger = await screen.findByRole("button", { name: /alpha/i });
    expect(trigger).toHaveAttribute("aria-expanded", "false");

    await user.click(trigger);
    expect(trigger).toHaveAttribute("aria-expanded", "true");

    const dialog = await screen.findByRole("dialog", { name: "Workspaces" });
    await waitFor(() => {
      expect(within(dialog).getByRole("button", { name: /alpha/i })).toHaveFocus();
    });

    for (let i = 0; i < 4; i += 1) {
      await user.tab();
      expect(dialog.contains(document.activeElement)).toBe(true);
    }

    await user.keyboard("{Escape}");

    await waitFor(() => {
      expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
    });
    await waitFor(() => {
      expect(trigger).toHaveFocus();
    });
    expect(trigger).toHaveAttribute("aria-expanded", "false");
  });

  it("keeps the current workspace selected when the next workspace has no id", async () => {
    const onChange = vi.fn();
    const user = userEvent.setup();

    renderWithProviders(
      <WorkspaceSelector
        value="alpha"
        workspaces={[
          makeWorkspace("alpha"),
          makeWorkspace("beta", {
            id: "",
            provision_state: "failed",
            container_state: "missing",
          }),
        ]}
        onChange={onChange}
      />,
      { locale: "en" },
    );

    await user.click(await screen.findByRole("button", { name: /alpha/i }));

    const betaOption = (await screen.findByText("beta")).closest("button");
    if (!betaOption) {
      throw new Error("beta workspace option not found");
    }

    await user.click(betaOption);

    expect(await screen.findByText("Couldn't prepare the workspace runtime.")).toBeInTheDocument();
    expect(onChange).not.toHaveBeenCalled();
  });

  it("shows a header-managed empty state when no workspaces exist", async () => {
    const user = userEvent.setup();

    renderWithProviders(
      <WorkspaceSelector value="" workspaces={[]} onChange={vi.fn()} />,
      { locale: "en" },
    );

    await user.click(await screen.findByRole("button", { name: /no workspaces/i }));

    expect(await screen.findByText("No workspaces yet")).toBeInTheDocument();
    expect(screen.getByText("Workspaces must be created outside the header picker.")).toBeInTheDocument();
  });
});
