#!/usr/bin/env node
import {
  ConfigManager
} from "./chunk-WLMBMRIA.js";
import "./chunk-TZQHYZKT.js";
import "./chunk-2DVGTYZG.js";
import "./chunk-PDX44BCA.js";

// src/cli/batch.ts
import Anthropic from "@anthropic-ai/sdk";
import { readFileSync, writeFileSync, existsSync, mkdirSync, renameSync, unlinkSync } from "fs";
import { join } from "path";
function parseBatchInput(jsonl) {
  const lines = jsonl.split("\n").map((l) => l.trim()).filter(Boolean);
  if (lines.length === 0) throw new Error("Input file is empty");
  if (lines.length > 1e5) throw new Error(`Too many requests: ${lines.length} (Anthropic limit: 100000)`);
  const seen = /* @__PURE__ */ new Set();
  const out = [];
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    let obj;
    try {
      obj = JSON.parse(line);
    } catch (err) {
      throw new Error(`Line ${i + 1}: invalid JSON (${err instanceof Error ? err.message : String(err)})`);
    }
    if (!obj || typeof obj !== "object") {
      throw new Error(`Line ${i + 1}: expected JSON object`);
    }
    const rec = obj;
    const customId = String(rec.customId ?? rec.custom_id ?? "");
    if (!customId) throw new Error(`Line ${i + 1}: missing customId`);
    if (!/^[A-Za-z0-9_-]{1,64}$/.test(customId)) {
      throw new Error(`Line ${i + 1}: customId "${customId}" must be 1-64 chars of [A-Za-z0-9_-]`);
    }
    if (seen.has(customId)) throw new Error(`Line ${i + 1}: duplicate customId "${customId}"`);
    seen.add(customId);
    const messages = rec.messages;
    if (!Array.isArray(messages) || messages.length === 0) {
      throw new Error(`Line ${i + 1}: messages must be a non-empty array`);
    }
    for (let j = 0; j < messages.length; j++) {
      const m = messages[j];
      if (!m || m.role !== "user" && m.role !== "assistant") {
        throw new Error(`Line ${i + 1}: messages[${j}].role must be 'user' or 'assistant'`);
      }
      if (typeof m.content !== "string") {
        throw new Error(`Line ${i + 1}: messages[${j}].content must be a string`);
      }
    }
    out.push({
      customId,
      messages,
      model: typeof rec.model === "string" ? rec.model : void 0,
      system: typeof rec.system === "string" ? rec.system : void 0,
      maxTokens: typeof rec.maxTokens === "number" ? rec.maxTokens : typeof rec.max_tokens === "number" ? rec.max_tokens : void 0
    });
  }
  return out;
}
function getBatchesPath(config) {
  return join(config.getConfigDir(), "batches.json");
}
function loadTrackedBatches(config) {
  const p = getBatchesPath(config);
  if (!existsSync(p)) return [];
  try {
    const data = JSON.parse(readFileSync(p, "utf-8"));
    return Array.isArray(data.batches) ? data.batches : [];
  } catch {
    return [];
  }
}
function saveTrackedBatches(config, batches) {
  mkdirSync(config.getConfigDir(), { recursive: true });
  const finalPath = getBatchesPath(config);
  const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
  try {
    writeFileSync(tmpPath, JSON.stringify({ batches }, null, 2), "utf-8");
    renameSync(tmpPath, finalPath);
  } catch (err) {
    try {
      unlinkSync(tmpPath);
    } catch {
    }
    throw err;
  }
}
function getClaudeClient(config) {
  const apiKey = config.getApiKey("claude");
  if (!apiKey) {
    throw new Error("No Claude API key configured. Run `aicli config` or set AICLI_API_KEY_CLAUDE.");
  }
  return new Anthropic({ apiKey });
}
function getDefaultModel(config) {
  const models = config.get("defaultModels");
  return models?.claude ?? "claude-sonnet-4-5-20250929";
}
async function cmdSubmit(inputFile, options = {}) {
  const config = new ConfigManager();
  if (!existsSync(inputFile)) throw new Error(`Input file not found: ${inputFile}`);
  const raw = readFileSync(inputFile, "utf-8");
  const requests = parseBatchInput(raw);
  const defaultModel = getDefaultModel(config);
  console.log(`Parsed ${requests.length} request(s) from ${inputFile}`);
  console.log(`Default model: ${defaultModel}`);
  if (options.dryRun) {
    console.log("[dry-run] Not submitting. Sample request:");
    console.log(JSON.stringify(requests[0], null, 2));
    return;
  }
  const client = getClaudeClient(config);
  const apiRequests = requests.map((r) => ({
    custom_id: r.customId,
    params: {
      model: r.model ?? defaultModel,
      max_tokens: r.maxTokens ?? 4096,
      messages: r.messages,
      ...r.system ? { system: r.system } : {}
    }
  }));
  console.log(`Submitting ${apiRequests.length} request(s) to Anthropic Batches API\u2026`);
  const batch = await client.messages.batches.create({ requests: apiRequests });
  const tracked = loadTrackedBatches(config);
  tracked.unshift({
    id: batch.id,
    provider: "claude",
    createdAt: (/* @__PURE__ */ new Date()).toISOString(),
    inputFile,
    requestCount: requests.length,
    model: defaultModel
  });
  saveTrackedBatches(config, tracked.slice(0, 200));
  console.log(`
Batch submitted:`);
  console.log(`  ID:              ${batch.id}`);
  console.log(`  Processing:      ${batch.processing_status}`);
  console.log(`  Expires:         ${batch.expires_at}`);
  console.log(`
Check status:  aicli batch status ${batch.id}`);
  console.log(`Get results:   aicli batch results ${batch.id}`);
}
async function cmdList() {
  const config = new ConfigManager();
  const tracked = loadTrackedBatches(config);
  if (tracked.length === 0) {
    console.log("No tracked batches. Submit one with `aicli batch submit <input.jsonl>`.");
    return;
  }
  const client = getClaudeClient(config);
  console.log(`
${tracked.length} tracked batch(es):
`);
  console.log("  ID                                        Requests  Status              Created");
  console.log("  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
  for (const b of tracked.slice(0, 20)) {
    let status = "(unknown)";
    try {
      const fresh = await client.messages.batches.retrieve(b.id);
      status = fresh.processing_status;
    } catch {
      status = "(fetch-failed)";
    }
    const created = new Date(b.createdAt).toLocaleString();
    console.log(`  ${b.id.padEnd(42)}  ${String(b.requestCount).padStart(8)}  ${status.padEnd(18)}  ${created}`);
  }
  console.log("");
}
async function cmdStatus(batchId) {
  const config = new ConfigManager();
  const client = getClaudeClient(config);
  const batch = await client.messages.batches.retrieve(batchId);
  console.log(`
Batch ${batch.id}`);
  console.log(`  Processing:      ${batch.processing_status}`);
  console.log(`  Created:         ${batch.created_at}`);
  console.log(`  Expires:         ${batch.expires_at}`);
  if (batch.ended_at) console.log(`  Ended:           ${batch.ended_at}`);
  const counts = batch.request_counts;
  if (counts) {
    console.log(`  Counts:          processing=${counts.processing} succeeded=${counts.succeeded} errored=${counts.errored} canceled=${counts.canceled} expired=${counts.expired}`);
  }
  if (batch.results_url) console.log(`  Results URL:     ${batch.results_url}`);
  console.log("");
}
async function cmdResults(batchId, outPath) {
  const config = new ConfigManager();
  const client = getClaudeClient(config);
  const batch = await client.messages.batches.retrieve(batchId);
  if (batch.processing_status !== "ended") {
    console.log(`Batch is not ready yet (status: ${batch.processing_status}). Try again later.`);
    return;
  }
  const stream = await client.messages.batches.results(batchId);
  const lines = [];
  let ok = 0, err = 0;
  for await (const result of stream) {
    lines.push(JSON.stringify(result));
    const type = result.result?.type;
    if (type === "succeeded") ok++;
    else err++;
  }
  const body = lines.join("\n") + "\n";
  if (outPath) {
    writeFileSync(outPath, body, "utf-8");
    console.log(`Saved ${lines.length} result(s) to ${outPath} (${ok} succeeded, ${err} failed/errored).`);
  } else {
    process.stdout.write(body);
    process.stderr.write(`
[Summary] ${lines.length} results: ${ok} succeeded, ${err} failed/errored.
`);
  }
}
async function cmdCancel(batchId) {
  const config = new ConfigManager();
  const client = getClaudeClient(config);
  const batch = await client.messages.batches.cancel(batchId);
  console.log(`Canceled batch ${batch.id} (status: ${batch.processing_status}).`);
}
export {
  cmdCancel,
  cmdList,
  cmdResults,
  cmdStatus,
  cmdSubmit,
  loadTrackedBatches,
  parseBatchInput,
  saveTrackedBatches
};
