import assert from "node:assert/strict";
import test from "node:test";

import {
  CodexAppServerRunHandle,
  decideCodexMcpElicitation,
} from "../CodexAppServerRunHandle.ts";

test("MCP elicitation accepts only configured and role-allowed FCoP tools", () => {
  const servers = {
    fcop: {
      command: "node",
      args: ["fcop-filter.js"],
      env: { FCOP_ALLOWED_TOOLS: "fcop_report,write_report" },
    },
  };
  const base = {
    serverName: "fcop",
    _meta: { codex_approval_kind: "mcp_tool_call" },
  };

  assert.equal(decideCodexMcpElicitation({
    ...base,
    message: 'Allow the fcop MCP server to run tool "fcop_report"?',
  }, servers).action, "accept");
  assert.equal(decideCodexMcpElicitation({
    ...base,
    message: 'Allow the fcop MCP server to run tool "archive_task"?',
  }, servers).action, "decline");
  assert.equal(decideCodexMcpElicitation({
    serverName: "unknown",
    _meta: { codex_approval_kind: "mcp_tool_call" },
    message: 'Allow tool "fcop_report"?',
  }, servers).action, "decline");
});

test("MCP elicitation treats lifecycle aliases as the configured canonical operation", () => {
  const servers = {
    fcop: {
      command: "node",
      args: ["fcop-filter.js"],
      env: { FCOP_ALLOWED_TOOLS: "submit_task,approve_task,reject_task" },
    },
  };
  const request = (tool: string) => decideCodexMcpElicitation({
    serverName: "fcop",
    _meta: { codex_approval_kind: "mcp_tool_call" },
    message: `Allow the fcop MCP server to run tool "${tool}"?`,
  }, servers).action;

  assert.equal(request("submit_review"), "accept");
  assert.equal(request("approve_review"), "accept");
  assert.equal(request("reject_review"), "accept");
  assert.equal(request("archive_task"), "decline");
});

test("app-server maps observable summaries, tool calls and completion", async () => {
  const handle = new CodexAppServerRunHandle({
    sessionId: "session-test",
    agentId: "PM-01",
    provider: "openai-chatgpt-subscription",
    model: "gpt-5.6-sol",
    workspace: "D:\\workspace",
    text: "inspect",
  });
  const events: Array<{ event_type: string; payload?: unknown }> = [];
  handle.onEvent((event) => events.push(event));

  handle.acceptMessageForTest({
    method: "item/reasoning/summaryTextDelta",
    params: { itemId: "reason-1", delta: "Checking evidence" },
  });
  handle.acceptMessageForTest({
    method: "item/started",
    params: {
      turnId: "turn-1",
      item: {
        id: "tool-1",
        type: "mcpToolCall",
        server: "fcop",
        tool: "fcop_report",
        arguments: { lang: "zh" },
      },
    },
  });
  handle.acceptMessageForTest({
    method: "item/completed",
    params: {
      turnId: "turn-1",
      item: {
        id: "tool-1",
        type: "mcpToolCall",
        server: "fcop",
        tool: "fcop_report",
        status: "completed",
        result: { ok: true },
        durationMs: 12,
      },
    },
  });
  handle.acceptMessageForTest({
    method: "item/completed",
    params: { item: { id: "msg-1", type: "agentMessage", text: "done" } },
  });
  handle.acceptMessageForTest({
    method: "turn/completed",
    params: { turn: { id: "turn-1", status: "completed" } },
  });

  const run = await handle.whenSettled();
  assert.equal(run.status, "finished");
  assert.equal(run.tool_calls_count, 1);
  assert.ok(events.some((event) => event.event_type === "sdk.status"));
  assert.ok(!events.some((event) => event.event_type === "sdk.thinking"));
  assert.ok(events.some((event) => event.event_type === "sdk.tool_call"));
  assert.ok(events.some((event) => event.event_type === "sdk.tool_result"));
  const toolCall = events.find((event) => event.event_type === "sdk.tool_call")
    ?.payload as Record<string, unknown>;
  const toolResult = events.find((event) => event.event_type === "sdk.tool_result")
    ?.payload as Record<string, unknown>;
  assert.equal(toolCall.tool_name, "fcop.fcop_report");
  assert.equal(toolCall.round_id, "turn-1");
  assert.match(String(toolCall.arguments_summary), /lang/);
  assert.equal(toolResult.exit_status, "completed");
  assert.equal(toolResult.duration_ms, 12);
  assert.ok(events.some((event) => event.event_type === "sdk.assistant"));
  assert.ok(events.some((event) => event.event_type === "sdk.result"));
});
