import { describe, expect, it } from "vitest";

import { CLAUDE_IDENTITY_PREFIX } from "../auto-reply/claude.js";
import { OPENCODE_IDENTITY_PREFIX } from "../auto-reply/opencode.js";
import { claudeSpec } from "./claude.js";
import { codexSpec } from "./codex.js";
import { opencodeSpec } from "./opencode.js";
import { piSpec } from "./pi.js";

describe("agent buildArgs + parseOutput helpers", () => {
  it("claudeSpec injects flags and identity once", () => {
    const argv = ["claude", "hi"];
    const built = claudeSpec.buildArgs({
      argv,
      bodyIndex: 1,
      isNewSession: true,
      sessionId: "sess",
      sendSystemOnce: false,
      systemSent: false,
      identityPrefix: undefined,
      format: "json",
    });
    expect(built).toContain("--output-format");
    expect(built).toContain("json");
    expect(built).toContain("-p");
    expect(built.at(-1)).toContain(CLAUDE_IDENTITY_PREFIX);

    const builtNoIdentity = claudeSpec.buildArgs({
      argv,
      bodyIndex: 1,
      isNewSession: false,
      sessionId: "sess",
      sendSystemOnce: true,
      systemSent: true,
      identityPrefix: undefined,
      format: "json",
    });
    expect(builtNoIdentity.at(-1)).not.toContain(CLAUDE_IDENTITY_PREFIX);
  });

  it("opencodeSpec adds format flag and identity prefix when needed", () => {
    const argv = ["opencode", "body"];
    const built = opencodeSpec.buildArgs({
      argv,
      bodyIndex: 1,
      isNewSession: true,
      sessionId: "sess",
      sendSystemOnce: false,
      systemSent: false,
      identityPrefix: undefined,
      format: "json",
    });
    expect(built).toContain("--format");
    expect(built).toContain("json");
    expect(built.at(-1)).toContain(OPENCODE_IDENTITY_PREFIX);
  });

  it("piSpec parses final assistant message and preserves usage meta", () => {
    const stdout = [
      '{"type":"message_start","message":{"role":"assistant"}}',
      '{"type":"message_end","message":{"role":"assistant","content":[{"type":"text","text":"hello world"}],"usage":{"input":10,"output":5},"model":"pi-1","provider":"inflection","stopReason":"end"}}',
    ].join("\n");
    const parsed = piSpec.parseOutput(stdout);
    expect(parsed.text).toBe("hello world");
    expect(parsed.meta?.provider).toBe("inflection");
    expect((parsed.meta?.usage as { output?: number })?.output).toBe(5);
  });

  it("codexSpec parses agent_message and aggregates usage", () => {
    const stdout = [
      '{"type":"item.completed","item":{"type":"agent_message","text":"hi there"}}',
      '{"type":"turn.completed","usage":{"input_tokens":50,"output_tokens":10,"cached_input_tokens":5}}',
    ].join("\n");
    const parsed = codexSpec.parseOutput(stdout);
    expect(parsed.text).toBe("hi there");
    const usage = parsed.meta?.usage as {
      input?: number;
      output?: number;
      cacheRead?: number;
      total?: number;
    };
    expect(usage?.input).toBe(50);
    expect(usage?.output).toBe(10);
    expect(usage?.cacheRead).toBe(5);
    expect(usage?.total).toBe(65);
  });

  it("opencodeSpec parses streamed events and summarizes meta", () => {
    const stdout = [
      '{"type":"step_start","timestamp":0}',
      '{"type":"text","part":{"text":"hi"}}',
      '{"type":"step_finish","timestamp":1200,"part":{"cost":0.002,"tokens":{"input":100,"output":20}}}',
    ].join("\n");
    const parsed = opencodeSpec.parseOutput(stdout);
    expect(parsed.text).toBe("hi");
    expect(parsed.meta?.extra?.summary).toContain("duration=1200ms");
    expect(parsed.meta?.extra?.summary).toContain("cost=$0.0020");
    expect(parsed.meta?.extra?.summary).toContain("tokens=100+20");
  });

  it("codexSpec buildArgs enforces exec/json/sandbox defaults", () => {
    const argv = ["codex", "hello world"];
    const built = codexSpec.buildArgs({
      argv,
      bodyIndex: 1,
      isNewSession: true,
      sessionId: "sess",
      sendSystemOnce: false,
      systemSent: false,
      identityPrefix: undefined,
      format: "json",
    });
    expect(built[1]).toBe("exec");
    expect(built).toContain("--json");
    expect(built).toContain("--skip-git-repo-check");
    expect(built).toContain("read-only");
  });
});
