import { codexOutputQuery, codexTaskQuery } from "./src/code-queue";

type JsonRecord = Record<string, unknown>;

function assertCondition(condition: unknown, message: string, detail: unknown = {}): void {
  if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}

function asRecord(value: unknown): JsonRecord {
  assertCondition(value !== null && typeof value === "object" && !Array.isArray(value), "expected object", { value });
  return value as JsonRecord;
}

function asArray(value: unknown): unknown[] {
  assertCondition(Array.isArray(value), "expected array", { value });
  return value as unknown[];
}

function longText(marker: string, repeat = 220): string {
  return Array.from({ length: repeat }, (_, index) => `${marker}-${String(index + 1).padStart(3, "0")} ${"abcdefghijklmnopqrstuvwxyz0123456789".repeat(3)}`).join("\n");
}

function detailFixture(path: string): JsonRecord {
  assertCondition(path.includes("/summary"), "detail fixture should only fetch summary", { path });
  return {
    ok: true,
    status: 200,
    body: {
      ok: true,
      summary: {
        id: "codex_disclosure_fixture",
        queueId: "noise",
        status: "failed",
        providerId: "D601",
        model: "gpt-5.5",
        cwd: "/workspace",
        prompt: longText("prompt-tail-marker"),
        basePrompt: longText("base-tail-marker"),
        transcriptCount: 300,
        outputCount: 180,
        eventCount: 40,
        lastAssistantMessage: {
          at: "2026-05-23T00:00:00.000Z",
          seq: 300,
          source: "assistant",
          text: longText("assistant-tail-marker"),
        },
        toolSummary: {
          count: 12,
          returned: 8,
          limit: 8,
          truncated: true,
          items: Array.from({ length: 8 }, (_, index) => ({
            seq: index + 1,
            at: "2026-05-23T00:00:00.000Z",
            kind: "ran",
            title: `tool-${index + 1}`,
            status: "ok",
            commandPreview: longText(`command-tail-marker-${index + 1}`, 20),
            outputPreview: longText(`tool-output-tail-marker-${index + 1}`, 20),
            rawSeqs: [index + 1],
          })),
        },
        attempts: Array.from({ length: 8 }, (_, index) => ({
          index: index + 1,
          mode: index === 0 ? "initial" : "retry",
          terminalStatus: "failed",
          stderrTail: longText(`stderr-tail-marker-${index + 1}`, 20),
          finalResponse: longText(`attempt-response-tail-marker-${index + 1}`, 30),
          feedbackPromptPreview: longText(`feedback-tail-marker-${index + 1}`, 20),
          runnerErrorClassification: { scope: "runner-local", globalBlocker: false },
        })),
      },
    },
  };
}

function outputFixture(path: string): JsonRecord {
  assertCondition(path.includes("/output"), "output fixture should fetch output", { path });
  assertCondition(path.includes("limit=20"), "default output should cap large requested limit to 20", { path });
  assertCondition(path.includes("maxTextChars=500"), "default output should cap text preview chars", { path });
  const output = Array.from({ length: 20 }, (_, index) => ({
    seq: index + 101,
    at: "2026-05-23T00:00:00.000Z",
    channel: index % 2 === 0 ? "command" : "assistant",
    method: "fixture",
    text: longText(`raw-output-tail-marker-${index + 1}`, 40),
  }));
  return {
    ok: true,
    status: 200,
    body: {
      ok: true,
      taskId: "codex_disclosure_fixture",
      queueId: "noise",
      status: "running",
      updatedAt: "2026-05-23T00:00:00.000Z",
      mode: "tail",
      limit: 20,
      total: 240,
      maxSeq: 1200,
      afterSeq: 0,
      nextAfterSeq: 120,
      previousBeforeSeq: 101,
      hasMore: true,
      hasBefore: true,
      output,
    },
  };
}

export function runCodeQueueCliDisclosureContract(): JsonRecord {
  const detail = codexTaskQuery("codex_disclosure_fixture", ["--detail"], detailFixture) as JsonRecord;
  const detailJson = JSON.stringify(detail);
  const summary = asRecord(detail.summary);
  const attempts = asRecord(summary.attempts);
  const attemptRecords = asArray(attempts.attemptRecords);
  const toolSummary = asRecord(summary.toolSummary);
  const toolItems = asArray(toolSummary.items);

  assertCondition(attemptRecords.length === 3, "detail should cap attempt records by default", attempts);
  assertCondition(attempts.attemptRecordCount === 8 && attempts.attemptRecordsTruncated === true, "detail should expose omitted attempt metadata", attempts);
  assertCondition(detailJson.includes("detailOutputPolicy"), "detail should disclose progressive detail policy", summary);
  assertCondition(!detailJson.includes("prompt-tail-marker-220"), "detail should not include full prompt tail by default", summary);
  assertCondition(!detailJson.includes("assistant-tail-marker-220"), "detail should not include full assistant tail by default", summary);
  assertCondition(!detailJson.includes("attempt-response-tail-marker-1-030"), "detail should not include full attempt response by default", attempts);
  assertCondition(toolItems.length === 3 && toolSummary.truncated === true, "detail should cap tool summary rows by default", toolSummary);
  assertCondition(!detailJson.includes("tool-output-tail-marker-1-020"), "detail should compact tool output previews", toolSummary);

  const output = codexOutputQuery("codex_disclosure_fixture", ["--tail", "--limit", "120"], outputFixture) as JsonRecord;
  const page = asRecord(output.outputPage);
  const outputRows = asArray(page.output).map(asRecord);
  const outputJson = JSON.stringify(output);
  const disclosure = asRecord(page.disclosure);
  assertCondition(page.requestedLimit === 120 && page.limit === 20 && page.returned === 20, "output should cap large requested limit by default", page);
  assertCondition(disclosure.limitCapped === true && disclosure.fullText === false, "output should disclose capped default policy", disclosure);
  assertCondition(outputRows.every((row) => row.textTruncated === true && Number(row.textChars) > String(row.text).length), "output rows should expose bounded text previews", page);
  assertCondition(!outputJson.includes("raw-output-tail-marker-1-040"), "output should not include full raw text tail by default", page);
  assertCondition(String(asRecord(page.commands).fullText).includes("--full-text"), "output should provide explicit full-text command", page);

  return {
    ok: true,
    checks: [
      "codex task --detail caps attempts and long text by default",
      "codex output caps large requested limits by default",
      "codex output preserves progressive full-text command",
    ],
    detailChars: detailJson.length,
    outputChars: outputJson.length,
  };
}

if (import.meta.main) {
  process.stdout.write(`${JSON.stringify(runCodeQueueCliDisclosureContract(), null, 2)}\n`);
}
