import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Actions } from "../Actions";
import type { SavedTask, ServiceInstance } from "../../types";

const saveTaskMutate = vi.fn().mockResolvedValue({
	id: "t1",
	name: "Restart svc",
	task_type: "shell",
	content: "",
	enabled: true,
	default_service_id: "",
	notes: "",
});
const deleteTaskMutate = vi.fn();
const runTaskMutate = vi.fn().mockResolvedValue({});

let sshServices: ServiceInstance[] = [];
let tasks: SavedTask[] = [];

vi.mock("../../hooks/useSettings", () => ({
	useTasks: () => ({ data: tasks }),
	useSaveTask: () => ({ mutateAsync: saveTaskMutate, isPending: false }),
	useDeleteTask: () => ({ mutate: deleteTaskMutate }),
	useRunTask: () => ({ mutateAsync: runTaskMutate, isPending: false }),
	useTaskRuns: () => ({ data: { items: [] } }),
}));

vi.mock("../../hooks/useServices", () => ({
	useServiceInstances: () => ({ data: sshServices }),
}));

function sshService(overrides: Partial<ServiceInstance> = {}): ServiceInstance {
	return {
		id: "s1",
		service_type: "ssh_tasks",
		name: "Box",
		config: { host: "box", username: "u" },
		secrets_set: {},
		enabled: true,
		created_at: 0,
		updated_at: 0,
		...overrides,
	} as ServiceInstance;
}

function task(overrides: Partial<SavedTask> = {}): SavedTask {
	return {
		id: "t1",
		name: "Restart svc",
		task_type: "shell",
		content: "systemctl restart foo",
		enabled: true,
		default_service_id: "",
		notes: "",
		created_at: 0,
		updated_at: 0,
		...overrides,
	} as SavedTask;
}

beforeEach(() => {
	saveTaskMutate.mockClear();
	deleteTaskMutate.mockClear();
	runTaskMutate.mockClear();
	sshServices = [];
	tasks = [];
});

describe("Actions", () => {
	it("shows the empty state and creates a task via the editor dialog", async () => {
		render(<Actions />);

		expect(screen.getByText("No action selected")).toBeInTheDocument();
		expect(
			screen.getByRole("button", { name: "Add action" }),
		).toBeInTheDocument();

		await userEvent.click(screen.getByRole("button", { name: "Add action" }));
		// Editor dialog opened (Name field is unique to the editor).
		expect(screen.getByLabelText("Name")).toBeInTheDocument();

		// Controlled input parity: name + default shell type flow through.
		await userEvent.type(screen.getByLabelText("Name"), "Restart svc");
		await userEvent.click(screen.getByRole("button", { name: "Save action" }));

		expect(saveTaskMutate).toHaveBeenCalledTimes(1);
		const saved = saveTaskMutate.mock.calls[0][0];
		expect(saved.name).toBe("Restart svc");
		expect(saved.task_type).toBe("shell");
		expect(saved.default_service_id).toBe("");
	});

	it("disables the Run button until a run service is selected", async () => {
		sshServices = [sshService()];
		tasks = [task()];
		render(<Actions />);

		// Selecting a saved task tab exposes the detail + Run control.
		await userEvent.click(screen.getByRole("tab", { name: "Restart svc" }));

		const runButton = screen.getByRole("button", { name: "Run action" });
		expect(runButton).toBeDisabled();
	});

	it("runs a task on the selected SSH task service", async () => {
		sshServices = [sshService()];
		tasks = [task()];
		render(<Actions />);

		await userEvent.click(screen.getByRole("tab", { name: "Restart svc" }));
		await userEvent.click(
			screen.getByRole("combobox", { name: "Run on SSH task service" }),
		);
		await userEvent.click(screen.getByRole("option", { name: "Box" }));
		await userEvent.click(screen.getByRole("button", { name: "Run action" }));

		expect(runTaskMutate).toHaveBeenCalledTimes(1);
		expect(runTaskMutate).toHaveBeenCalledWith({
			taskId: "t1",
			serviceId: "s1",
		});
	});
});
