// Cockpit cancel.
//
// `POST /api/sessions/:id/cockpit/cancel` forwards a `session/cancel`
// notification to the live ACP agent, which is expected to emit
// `stopped { reason: "cancelled" }` mid-turn so the UI can clear its
// spinner.
//
// Skipped pending #1237. This spec needs an in-flight prompt to cancel,
// and the prompt-side path currently surfaces
// `AgentStartupError { message: "ACP connection failed: Authentication
// required" }` between UserPromptSent and the scripted update emission.
// Unskip once #1237 is resolved.

import { mkdtempSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { test as base, expect } from "@playwright/test";
import {
  spawnAoeServe,
  listSessions,
  seedSessionViaAoeAdd,
} from "../helpers/aoeServe";

const SLOW_TURN_SCRIPT = {
  turns: [
    {
      updates: [
        {
          sessionUpdate: "agent_message_chunk",
          content: { type: "text", text: "Thinking..." },
        },
        // The cancel notification should land between this chunk and
        // the final stop. The fake agent's `session/cancel` handler
        // emits `stopped { stopReason: "cancelled" }`, but only when
        // the prompt path actually reaches the agent.
      ],
      stopReason: "end_turn",
    },
  ],
};

base.skip("cockpit/cancel publishes Stopped reason:cancelled mid-turn", async ({}, testInfo) => {
  const scriptDir = mkdtempSync(join(tmpdir(), "aoe-pw-cancel-"));
  const scriptPath = join(scriptDir, "script.json");
  writeFileSync(scriptPath, JSON.stringify(SLOW_TURN_SCRIPT));

  const serve = await spawnAoeServe({
    authMode: "none",
    cockpit: true,
    fakeAcpScript: scriptPath,
    workerIndex: testInfo.workerIndex,
    parallelIndex: testInfo.parallelIndex,
    seedFn: seedSessionViaAoeAdd({ title: "cockpit-cancel" }),
  });

  try {
    const sessions = await listSessions(serve.baseUrl);
    const sessionId = sessions[0]!.id;

    await fetch(
      `${serve.baseUrl}/api/sessions/${sessionId}/cockpit/enable`,
      { method: "POST" },
    );
    await new Promise((r) => setTimeout(r, 2_000));

    await fetch(`${serve.baseUrl}/api/sessions/${sessionId}/cockpit/prompt`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ text: "long-running thought" }),
    });

    const cancelRes = await fetch(
      `${serve.baseUrl}/api/sessions/${sessionId}/cockpit/cancel`,
      { method: "POST" },
    );
    expect(cancelRes.status).toBe(202);

    let sawCancelled = false;
    for (let attempt = 0; attempt < 30; attempt++) {
      const replay = await fetch(
        `${serve.baseUrl}/api/sessions/${sessionId}/cockpit/replay?since=0`,
      ).then((r) => r.json());
      if (JSON.stringify(replay).includes("cancelled")) {
        sawCancelled = true;
        break;
      }
      await new Promise((r) => setTimeout(r, 200));
    }
    expect(sawCancelled).toBe(true);
  } finally {
    await serve.stop();
  }
});
