import { mkdtemp, rm, mkdir } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { ErrorCode } from "@pocketcoder/shared/constants";
import { openDatabase, closeDatabase } from "../../db/database.js";
import { createProject } from "../../db/repositories/projects.js";
import { handleAgentCancel } from "../agent-cancel.js";
// Suppress logger output in tests
vi.mock("../../utils/logger.js", () => ({
    logger: {
        debug: vi.fn(),
        info: vi.fn(),
        warn: vi.fn(),
        error: vi.fn(),
    },
}));
// Mock the OpenCode proxy
vi.mock("../../opencode/proxy.js", () => ({
    proxyToOpenCode: vi.fn(),
}));
import { proxyToOpenCode } from "../../opencode/proxy.js";
const mockProxyToOpenCode = vi.mocked(proxyToOpenCode);
describe("agent_cancel handler", () => {
    let tempDir;
    let projectDir;
    let dbPath;
    let projectId;
    const agentSessionId = "10ca3c7c-ece4-4c98-a251-365dad2a34ad";
    beforeEach(async () => {
        tempDir = await mkdtemp(join(tmpdir(), "pocketcoder-agent-cancel-test-"));
        projectDir = join(tempDir, "project");
        dbPath = join(tempDir, "daemon.db");
        await mkdir(projectDir);
        closeDatabase();
        openDatabase(dbPath);
        const project = createProject("test-project", projectDir);
        projectId = project.project_id;
        mockProxyToOpenCode.mockReset();
    });
    afterEach(async () => {
        closeDatabase();
        await rm(tempDir, { recursive: true, force: true });
    });
    function createRequest(sessionIdArg = agentSessionId) {
        return {
            type: "agent_cancel",
            requestId: "req-cancel-1",
            sessionId: projectId,
            payload: { agentSessionId: sessionIdArg },
        };
    }
    function createSendCollector() {
        const messages = [];
        const send = (msg) => {
            messages.push(msg);
        };
        return { messages, send };
    }
    it("should call POST /session/:id/abort via OpenCode API", async () => {
        mockProxyToOpenCode.mockResolvedValue({
            status: 200,
            headers: {},
            body: "",
        });
        const { messages, send } = createSendCollector();
        await handleAgentCancel(createRequest(), send);
        expect(mockProxyToOpenCode).toHaveBeenCalledWith({
            method: "POST",
            path: `/session/${agentSessionId}/abort`,
        });
        // No response sent - done event comes via SSE
        expect(messages).toHaveLength(0);
    });
    it("should handle 204 response as success", async () => {
        mockProxyToOpenCode.mockResolvedValue({
            status: 204,
            headers: {},
            body: "",
        });
        const { messages, send } = createSendCollector();
        await handleAgentCancel(createRequest(), send);
        expect(mockProxyToOpenCode).toHaveBeenCalled();
        expect(messages).toHaveLength(0);
    });
    it("should handle 404 gracefully (session already finished)", async () => {
        mockProxyToOpenCode.mockResolvedValue({
            status: 404,
            headers: {},
            body: "",
        });
        const { messages, send } = createSendCollector();
        await handleAgentCancel(createRequest("non-running-session"), send);
        expect(mockProxyToOpenCode).toHaveBeenCalled();
        // No error sent - gracefully handled
        expect(messages).toHaveLength(0);
    });
    it("should error for non-existent project", async () => {
        const msg = {
            type: "agent_cancel",
            requestId: "req-cancel-2",
            sessionId: "non-existent-project",
            payload: { agentSessionId: "session-123" },
        };
        const { messages, send } = createSendCollector();
        await handleAgentCancel(msg, send);
        expect(messages).toHaveLength(1);
        expect(messages[0]).toMatchObject({
            type: "error",
            requestId: "req-cancel-2",
            error: {
                code: ErrorCode.INVALID_REQUEST,
            },
        });
        expect(mockProxyToOpenCode).not.toHaveBeenCalled();
    });
    it("should error for missing agentSessionId", async () => {
        const msg = {
            type: "agent_cancel",
            requestId: "req-cancel-3",
            sessionId: projectId,
            payload: { agentSessionId: "" },
        };
        const { messages, send } = createSendCollector();
        await handleAgentCancel(msg, send);
        expect(messages).toHaveLength(1);
        expect(messages[0]).toMatchObject({
            type: "error",
            requestId: "req-cancel-3",
            error: {
                code: ErrorCode.INVALID_REQUEST,
                message: "agentSessionId is required for agent_cancel",
            },
        });
        expect(mockProxyToOpenCode).not.toHaveBeenCalled();
    });
    it("should handle OpenCode unreachable gracefully", async () => {
        mockProxyToOpenCode.mockRejectedValue(new Error("OPENCODE_UNREACHABLE"));
        const { messages, send } = createSendCollector();
        await handleAgentCancel(createRequest(), send);
        // No error message sent - just logged
        expect(messages).toHaveLength(0);
    });
    it("should handle other errors gracefully", async () => {
        mockProxyToOpenCode.mockRejectedValue(new Error("Connection refused"));
        const { messages, send } = createSendCollector();
        await handleAgentCancel(createRequest(), send);
        // No error message sent - just logged
        expect(messages).toHaveLength(0);
    });
});
//# sourceMappingURL=agent-cancel.test.js.map