// @bun
import {
  fetchProcesses
} from "./chunk-zv1d3rna.js";
import {
  cleanupConsoleFiles,
  forceKillConsole,
  shutdownConsole,
  waitForConsoleDead
} from "./chunk-e5m20bzw.js";
import {
  ensureJsonOnlyFormat
} from "./chunk-5zqmmchg.js";
import {
  failEarly
} from "./chunk-mnqhm7q2.js";
import {
  isAdkDevConsolePort,
  readConsolePort
} from "./chunk-damz8wsc.js";
import {
  findAgentRoot
} from "./chunk-6fad0ts7.js";
import {
  createCliLogger
} from "./chunk-t993tmz7.js";
import"./chunk-px7fts59.js";
import"./chunk-7krp2mgz.js";
import"./chunk-np5wcwfv.js";
import"./chunk-je8v6rhj.js";
import"./chunk-6w0knnta.js";
import"./chunk-w15xmtkn.js";
import"./chunk-3sd5p4qp.js";
import"./chunk-nh2akp42.js";
import"./chunk-kat1bv74.js";
import"./chunk-2a5b6azq.js";
import"./chunk-s8cp3qe6.js";
import"./chunk-fv5teh9w.js";
import"./chunk-8ab2w9a1.js";
import"./chunk-3xrpxgq4.js";
import"./chunk-w346ejn9.js";
import"./chunk-n8gath4k.js";
import"./chunk-v3ens42y.js";
import"./chunk-8839jtgk.js";
import"./chunk-s2akeqpw.js";
import"./chunk-6771vrjp.js";
import"./chunk-g8mm42v1.js";
import"./chunk-0q5d80bn.js";
import"./chunk-300xaact.js";
import"./chunk-b8c41yvb.js";
import"./chunk-jsqe5am4.js";
import"./chunk-m4c14gcg.js";
import"./chunk-gspjbr79.js";
import"./chunk-wesykvkp.js";
import"./chunk-gzj56z73.js";
import"./chunk-dhs2bg35.js";

// src/commands/adk-kill.ts
import path from "path";
var CONSOLE_ALIASES = new Set(["console", "ui", "devconsole", "dev-console", "devConsole"]);
var FETCH_TIMEOUT_MS = 1e4;
function resolveAgentTarget(target, agents) {
  const normalizedTarget = target.toLowerCase();
  const matches = [];
  const asPid = parseInt(target, 10);
  if (!isNaN(asPid) && String(asPid) === target) {
    for (const agent of agents) {
      if (agent.process?.adkPid === asPid || agent.process?.botPid === asPid) {
        if (!matches.includes(agent))
          matches.push(agent);
      }
    }
    if (matches.length > 0)
      return matches;
  }
  for (const agent of agents) {
    const agentPathLower = agent.agentPath.toLowerCase();
    const agentBasename = path.basename(agent.agentPath).toLowerCase();
    const agentName = agent.name.toLowerCase();
    if (agentPathLower === normalizedTarget || agent.agentPath === target) {
      if (!matches.includes(agent))
        matches.push(agent);
      continue;
    }
    if (agentBasename === normalizedTarget || agentPathLower.includes(normalizedTarget)) {
      if (!matches.includes(agent))
        matches.push(agent);
      continue;
    }
    if (agentName === normalizedTarget) {
      if (!matches.includes(agent))
        matches.push(agent);
      continue;
    }
  }
  return matches;
}
async function terminateAgentGracefully(port, agentPath) {
  try {
    const res = await fetch(`http://localhost:${port}/api/agents/terminate`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ agentPath }),
      signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
    });
    if (!res.ok) {
      const body2 = await res.json().catch(() => null);
      return {
        status: "failed",
        error: body2?.message ?? `Terminate request returned HTTP ${res.status}`
      };
    }
    const body = await res.json();
    return {
      status: body.status ?? "stopped",
      graceful: body.graceful,
      forced: body.forced,
      signal: body.signal
    };
  } catch (err) {
    return {
      status: "failed",
      error: err instanceof Error ? err.message : String(err)
    };
  }
}
async function waitForAgentsGone(port, agentPaths, timeoutMs = 6000) {
  const start = Date.now();
  while (Date.now() - start < timeoutMs) {
    const data2 = await fetchProcesses(port).catch(() => null);
    if (!data2)
      break;
    const remaining = data2.agents.filter((a) => agentPaths.has(a.agentPath) && a.consoleMode !== "cloud");
    if (remaining.length === 0)
      return [];
    await new Promise((resolve) => setTimeout(resolve, 250));
  }
  const data = await fetchProcesses(port).catch(() => null);
  if (!data)
    return [];
  return data.agents.filter((a) => agentPaths.has(a.agentPath) && a.consoleMode !== "cloud").map((a) => a.agentPath);
}
function forceKillPid(pid) {
  try {
    process.kill(pid, "SIGKILL");
    return true;
  } catch {
    return false;
  }
}
async function adkKill(positionalTargets, options = {}) {
  ensureJsonOnlyFormat(options.format);
  const logger = createCliLogger({ format: options.format });
  const hasTargets = positionalTargets.length > 0 || options.all || options.current || (options.pid?.length ?? 0) > 0;
  if (!hasTargets) {
    const msg = `No targets specified. Use --all, --current, --pid <pid>, or provide agent path/name arguments.

` + `Examples:
` + `  adk kill --current                # stop the agent in the current directory
` + `  adk kill my-agent                 # stop by name or path
` + `  adk kill --all                    # stop all agents and the DevConsole
` + "  adk kill --pid 12345              # stop by ADK process PID";
    return failEarly(logger, options.format, msg, {
      targets: [],
      killed: [],
      failed: [],
      dryRun: options.dryRun ?? false,
      all: options.all ?? false,
      consoleCleanup: "not-applicable"
    });
  }
  for (const t of positionalTargets) {
    if (CONSOLE_ALIASES.has(t.toLowerCase())) {
      const msg = `Cannot kill the DevConsole by name ('${t}' is a reserved alias). ` + "Use --all to stop all agents and then shut down the DevConsole.";
      return failEarly(logger, options.format, msg, {
        targets: positionalTargets,
        killed: [],
        failed: [{ agentPath: t, status: "failed", error: msg }],
        dryRun: options.dryRun ?? false,
        all: options.all ?? false,
        consoleCleanup: "not-applicable"
      });
    }
  }
  const port = readConsolePort();
  if (port === null) {
    const msg = "No DevConsole is running. Start one with `adk dev` or `adk dashboard`.";
    return failEarly(logger, options.format, msg, {
      targets: positionalTargets,
      killed: [],
      failed: [],
      dryRun: options.dryRun ?? false,
      all: options.all ?? false,
      consoleCleanup: "not-applicable"
    });
  }
  if (!await isAdkDevConsolePort(port)) {
    const msg = `~/.adk/console.port points at port ${port}, but no ADK DevConsole is listening there. Remove stale files with: rm ~/.adk/console.lock ~/.adk/console.port ~/.adk/console.sock`;
    return failEarly(logger, options.format, msg, {
      targets: positionalTargets,
      killed: [],
      failed: [],
      dryRun: options.dryRun ?? false,
      all: options.all ?? false,
      consoleCleanup: "not-applicable"
    });
  }
  const data = await fetchProcesses(port);
  if (!data) {
    const msg = `Failed to fetch process list from DevConsole at port ${port}`;
    return failEarly(logger, options.format, msg, {
      targets: positionalTargets,
      killed: [],
      failed: [],
      dryRun: options.dryRun ?? false,
      all: options.all ?? false,
      consoleCleanup: "not-applicable"
    });
  }
  const localAgents = data.agents.filter((a) => a.consoleMode !== "cloud");
  let resolvedAgents = [];
  const unresolvedTargets = [];
  if (options.all) {
    resolvedAgents = [...localAgents];
  } else {
    if (options.current) {
      const agentRoot = await findAgentRoot(process.cwd());
      if (!agentRoot) {
        const msg = "No ADK project found in the current directory or its parents. Cannot use --current.";
        return failEarly(logger, options.format, msg, {
          targets: ["--current"],
          killed: [],
          failed: [{ agentPath: "--current", status: "failed", error: msg }],
          dryRun: options.dryRun ?? false,
          all: false,
          consoleCleanup: "not-applicable"
        });
      }
      const agent = localAgents.find((a) => a.agentPath === agentRoot);
      if (!agent) {
        const msg = `No running agent found for current project at ${agentRoot}`;
        return failEarly(logger, options.format, msg, {
          targets: [agentRoot],
          killed: [],
          failed: [{ agentPath: agentRoot, status: "failed", error: msg }],
          dryRun: options.dryRun ?? false,
          all: false,
          consoleCleanup: "not-applicable"
        });
      }
      if (!resolvedAgents.includes(agent))
        resolvedAgents.push(agent);
    }
    if (options.pid?.length) {
      for (const pid of options.pid) {
        const matched = localAgents.filter((a) => a.process?.adkPid === pid || a.process?.botPid === pid);
        if (matched.length === 0) {
          unresolvedTargets.push(`--pid ${pid}`);
        } else {
          for (const a of matched) {
            if (!resolvedAgents.includes(a))
              resolvedAgents.push(a);
          }
        }
      }
    }
    for (const target of positionalTargets) {
      const matches = resolveAgentTarget(target, localAgents);
      if (matches.length === 0) {
        unresolvedTargets.push(target);
      } else if (matches.length > 1) {
        const matchPaths = matches.map((a) => a.agentPath).join(`
  - `);
        const msg = `Ambiguous target '${target}': matched multiple agents. Use a more specific path or name.
` + `Matched:
  - ${matchPaths}`;
        return failEarly(logger, options.format, msg, {
          targets: positionalTargets,
          killed: [],
          failed: [{ agentPath: target, status: "failed", error: msg }],
          dryRun: options.dryRun ?? false,
          all: false,
          consoleCleanup: "not-applicable"
        });
      } else {
        const [agent] = matches;
        if (!resolvedAgents.includes(agent))
          resolvedAgents.push(agent);
      }
    }
    if (unresolvedTargets.length > 0) {
      const msg = `No running agent found for target(s): ${unresolvedTargets.join(", ")}`;
      return failEarly(logger, options.format, msg, {
        targets: [...positionalTargets, ...options.pid?.map((p) => `--pid ${p}`) ?? []],
        killed: [],
        failed: unresolvedTargets.map((t) => ({ agentPath: t, status: "failed", error: msg })),
        dryRun: options.dryRun ?? false,
        all: false,
        consoleCleanup: "not-applicable"
      });
    }
  }
  const targetPaths = resolvedAgents.map((a) => a.agentPath);
  if (options.dryRun) {
    const consoleCleanup2 = options.all ? "skipped" : "not-applicable";
    if (options.format !== "json") {
      if (resolvedAgents.length === 0) {
        logger.info("No agents to stop (dry run)");
      } else {
        logger.info("Dry run \u2014 the following agents would be stopped:");
        for (const agent of resolvedAgents) {
          logger.info(`  ${agent.name} (${agent.agentPath})`);
        }
        if (options.all) {
          logger.info("  DevConsole would also be shut down after all agents stop.");
        }
      }
    }
    const output2 = {
      targets: targetPaths,
      killed: resolvedAgents.map((a) => ({
        agentPath: a.agentPath,
        status: "dry-run"
      })),
      failed: [],
      dryRun: true,
      all: options.all ?? false,
      consoleCleanup: consoleCleanup2
    };
    if (options.format === "json") {
      logger.info("Dry run").result(output2);
    }
    return output2;
  }
  const killed = [];
  const failed = [];
  for (const agent of resolvedAgents) {
    if (options.format !== "json") {
      logger.info(`Stopping ${agent.name} (${agent.agentPath})...`);
    }
    const result = await terminateAgentGracefully(port, agent.agentPath);
    if (result.status === "failed") {
      if (options.force && agent.process?.adkPid) {
        const killed_ok = forceKillPid(agent.process.adkPid);
        if (killed_ok) {
          killed.push({
            agentPath: agent.agentPath,
            status: "forced",
            graceful: false,
            forced: true,
            signal: "SIGKILL"
          });
          if (options.format !== "json") {
            logger.info(`  \u2713 Force killed (SIGKILL, adkPid: ${agent.process.adkPid})`);
          }
        } else {
          failed.push({
            agentPath: agent.agentPath,
            status: "failed",
            error: result.error
          });
          if (options.format !== "json") {
            logger.error(`  \u2717 Failed: ${result.error}`);
          }
        }
      } else if (options.force && !agent.process?.adkPid) {
        failed.push({
          agentPath: agent.agentPath,
          status: "not-forceable",
          error: "No adkPid available for force kill (graceful also failed)"
        });
        if (options.format !== "json") {
          logger.warn(`  \u26A0 Not forceable: no PID metadata available. Graceful error: ${result.error ?? "unknown"}`);
        }
      } else {
        failed.push({
          agentPath: agent.agentPath,
          status: "failed",
          error: result.error
        });
        if (options.format !== "json") {
          logger.error(`  \u2717 Failed: ${result.error ?? "unknown error"} (use --force to force kill)`);
        }
      }
    } else {
      const killedResult = {
        agentPath: agent.agentPath,
        status: result.status === "shutdown-requested" ? "shutdown-requested" : "stopped",
        graceful: result.graceful,
        forced: result.forced,
        signal: result.signal
      };
      killed.push(killedResult);
      if (options.format !== "json") {
        if (result.status === "shutdown-requested") {
          logger.info(`  \u2713 Shutdown requested (graceful signal sent, process exiting in background)`);
        } else if (result.forced) {
          logger.info(`  \u2713 Stopped (forced, signal: ${result.signal ?? "SIGTERM/SIGKILL"})`);
        } else {
          logger.info(`  \u2713 Stopped gracefully`);
        }
      }
    }
  }
  let consoleCleanup = options.all ? "skipped" : "not-applicable";
  let consoleCleanupError;
  if (options.all) {
    const agentPathSet = new Set(targetPaths);
    if (agentPathSet.size > 0) {
      if (options.format !== "json") {
        logger.info("Waiting for agents to disconnect...");
      }
      const remaining = await waitForAgentsGone(port, agentPathSet);
      if (remaining.length > 0 && options.format !== "json") {
        logger.warn(`Some agents may still be running: ${remaining.join(", ")}`);
      }
    }
    if (options.format !== "json") {
      logger.info("Requesting DevConsole shutdown...");
    }
    const consolePid = data.console.pid;
    const shutdown = await shutdownConsole(port);
    if (shutdown.result === "success") {
      const dead = await waitForConsoleDead(port);
      if (dead) {
        consoleCleanup = "success";
        if (options.format !== "json") {
          logger.info("  \u2713 DevConsole shut down");
        }
      } else if (consolePid > 0) {
        if (options.format !== "json") {
          logger.warn("  \u26A0 DevConsole did not exit in time, force killing...");
        }
        const fk = await forceKillConsole(consolePid);
        if (fk.killed) {
          consoleCleanup = "success";
          if (options.format !== "json") {
            logger.info(`  \u2713 DevConsole force killed (${fk.signal}, PID ${consolePid})`);
          }
        } else {
          consoleCleanup = "failed";
          consoleCleanupError = `DevConsole PID ${consolePid} did not respond to SIGTERM/SIGKILL`;
          if (options.format !== "json") {
            logger.error(`  \u2717 ${consoleCleanupError}`);
          }
        }
      } else {
        consoleCleanup = "success";
        if (options.format !== "json") {
          logger.info("  \u2713 DevConsole shutdown requested (PID unknown, cannot verify exit)");
        }
      }
    } else if (shutdown.result === "unavailable" || shutdown.result === "failed") {
      if (consolePid > 0) {
        if (options.format !== "json") {
          const reason = shutdown.result === "unavailable" ? "endpoint unavailable (older version)" : `endpoint failed: ${shutdown.error ?? "unknown"}`;
          logger.warn(`  \u26A0 Graceful shutdown ${reason}, force killing PID ${consolePid}...`);
        }
        const fk = await forceKillConsole(consolePid);
        if (fk.killed) {
          consoleCleanup = "success";
          if (options.format !== "json") {
            logger.info(`  \u2713 DevConsole force killed (${fk.signal}, PID ${consolePid})`);
          }
        } else {
          consoleCleanup = "failed";
          consoleCleanupError = `DevConsole PID ${consolePid} did not respond to SIGTERM/SIGKILL`;
          if (options.format !== "json") {
            logger.error(`  \u2717 ${consoleCleanupError}`);
          }
        }
      } else {
        consoleCleanup = "failed";
        consoleCleanupError = shutdown.result === "unavailable" ? "Shutdown endpoint unavailable and no PID known for force kill" : `Shutdown failed: ${shutdown.error ?? "unknown"}, and no PID known for force kill`;
        if (options.format !== "json") {
          logger.error(`  \u2717 ${consoleCleanupError}`);
        }
      }
    }
    const removedFiles = cleanupConsoleFiles();
    if (removedFiles.length > 0 && options.format !== "json") {
      logger.info(`  Cleaned up: ${removedFiles.map((f) => `~/.adk/${f}`).join(", ")}`);
    }
  }
  const output = {
    targets: targetPaths,
    killed,
    failed,
    dryRun: false,
    all: options.all ?? false,
    consoleCleanup,
    ...consoleCleanupError ? { consoleCleanupError } : {}
  };
  if (options.format === "json") {
    logger.info(`Kill complete`).result(output);
  } else {
    if (killed.length > 0 || failed.length > 0) {
      logger.newline();
      logger.info(`Done: ${killed.length} stopped, ${failed.length} failed` + (consoleCleanup !== "not-applicable" ? `, console cleanup: ${consoleCleanup}` : ""));
    } else if (resolvedAgents.length === 0) {
      logger.info("No agents were running.");
    }
  }
  return output;
}
export {
  adkKill
};
