import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { AgentInfo, AgentConfigInfo } from "../api/agents";
import { agentsApi } from "../api/agents";

vi.mock("../api/agents", () => {
	const agentsApi = {
		listAgents: vi.fn(),
		getAgentConfig: vi.fn(),
		startAgent: vi.fn(),
		stopAgent: vi.fn(),
		reloadConfig: vi.fn(),
	};
	return { agentsApi, subscribeAgentStream: vi.fn(() => () => {}) };
});

// Dynamic import so the mock is in place before the module loads
const { AgentPanel } = await import("./AgentPanel");

const mockedAgents = {
	listAgents: vi.mocked(agentsApi.listAgents),
	getAgentConfig: vi.mocked(agentsApi.getAgentConfig),
	startAgent: vi.mocked(agentsApi.startAgent),
};

const ROSTER: AgentConfigInfo[] = [
	{
		name: "coder-1",
		role: "Full-stack engineer",
		model: "sonnet",
		allowed_tools: null,
		max_turns: 50,
		max_budget_usd: 5.0,
	},
];

describe("AgentPanel diff command", () => {
	beforeAll(() => {
		Element.prototype.scrollIntoView = vi.fn();
	});

	beforeEach(() => {
		mockedAgents.getAgentConfig.mockResolvedValue(ROSTER);
		mockedAgents.listAgents.mockResolvedValue([]);
	});

	it("shows diff command when an agent has a worktree path", async () => {
		const agentList: AgentInfo[] = [
			{
				story_id: "33_diff_commands",
				agent_name: "coder-1",
				status: "running",
				session_id: null,
				worktree_path: "/tmp/project-story-33",
				base_branch: "master",
			},
		];
		mockedAgents.listAgents.mockResolvedValue(agentList);

		render(
			<AgentPanel
				stories={[
					{ story_id: "33_diff_commands", name: "Diff Commands", error: null },
				]}
			/>,
		);

		// Expand the agent detail by clicking the expand button
		const expandButton = await screen.findByText("▶");
		await userEvent.click(expandButton);

		// The diff command should be rendered
		expect(
			await screen.findByText(
				'cd "/tmp/project-story-33" && git difftool master...HEAD',
			),
		).toBeInTheDocument();

		// A copy button should exist
		expect(screen.getByText("Copy")).toBeInTheDocument();
	});

	it("copies diff command to clipboard on click", async () => {
		const writeText = vi.fn().mockResolvedValue(undefined);
		Object.assign(navigator, {
			clipboard: { writeText },
		});

		const agentList: AgentInfo[] = [
			{
				story_id: "33_diff_commands",
				agent_name: "coder-1",
				status: "completed",
				session_id: null,
				worktree_path: "/home/user/my-project-story-33",
				base_branch: "main",
			},
		];
		mockedAgents.listAgents.mockResolvedValue(agentList);

		render(
			<AgentPanel
				stories={[
					{ story_id: "33_diff_commands", name: "Diff Commands", error: null },
				]}
			/>,
		);

		const expandButton = await screen.findByText("▶");
		await userEvent.click(expandButton);

		const copyButton = await screen.findByText("Copy");
		await userEvent.click(copyButton);

		await waitFor(() => {
			expect(writeText).toHaveBeenCalledWith(
				'cd "/home/user/my-project-story-33" && git difftool main...HEAD',
			);
		});

		expect(await screen.findByText("Copied")).toBeInTheDocument();
	});

	it("uses base_branch from the server in the diff command", async () => {
		const agentList: AgentInfo[] = [
			{
				story_id: "33_diff_commands",
				agent_name: "coder-1",
				status: "running",
				session_id: null,
				worktree_path: "/tmp/wt",
				base_branch: "develop",
			},
		];
		mockedAgents.listAgents.mockResolvedValue(agentList);

		render(
			<AgentPanel
				stories={[
					{ story_id: "33_diff_commands", name: "Diff Commands", error: null },
				]}
			/>,
		);

		const expandButton = await screen.findByText("▶");
		await userEvent.click(expandButton);

		expect(
			await screen.findByText(
				'cd "/tmp/wt" && git difftool develop...HEAD',
			),
		).toBeInTheDocument();
	});

	it("defaults to master when base_branch is null", async () => {
		const agentList: AgentInfo[] = [
			{
				story_id: "33_diff_commands",
				agent_name: "coder-1",
				status: "running",
				session_id: null,
				worktree_path: "/tmp/wt",
				base_branch: null,
			},
		];
		mockedAgents.listAgents.mockResolvedValue(agentList);

		render(
			<AgentPanel
				stories={[
					{ story_id: "33_diff_commands", name: "Diff Commands", error: null },
				]}
			/>,
		);

		const expandButton = await screen.findByText("▶");
		await userEvent.click(expandButton);

		expect(
			await screen.findByText(
				'cd "/tmp/wt" && git difftool master...HEAD',
			),
		).toBeInTheDocument();
	});
});
