import { exec, execScript } from "../ssh";
import type { AgentRunner, AgentRunnerCtx } from "./types";

// OpenCode: cài qua npm global. Daemon hoá bằng systemd nếu user chọn (tuỳ tham số agent).
// Bố trí: /opt/<name>/ chứa .env + workdir; binary lấy từ npm prefix.

function unitName(ctx: AgentRunnerCtx) {
  return `agent-${ctx.name}.service`;
}

function workdir(ctx: AgentRunnerCtx) {
  return `${ctx.installPath}/${ctx.name}`;
}

const SYSTEMD_TEMPLATE = (name: string, wd: string, envFile: string) => `
[Unit]
Description=Agent-Manager managed OpenCode (${name})
After=network.target

[Service]
Type=simple
WorkingDirectory=${wd}
EnvironmentFile=-${envFile}
ExecStart=/usr/bin/opencode serve --port \${OPENCODE_PORT:-4096}
Restart=on-failure
RestartSec=5
StandardOutput=append:/var/log/agent-${name}.log
StandardError=append:/var/log/agent-${name}.log

[Install]
WantedBy=multi-user.target
`.trim();

export const opencodeRunner: AgentRunner = {
  kind: "opencode",

  async install(ctx) {
    const wd = workdir(ctx);
    const envFile = `${wd}/.env`;
    const unit = unitName(ctx);
    const r = await execScript(ctx.hostId, [
      { label: "base deps", cmd: "apt-get update -q 2>&1 | tail -3 && DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl ca-certificates gnupg 2>&1 | tail -3" },
      { label: "ensure node 20", cmd: "node -v 2>/dev/null | grep -qE '^v(2[0-9]|[3-9][0-9])' || (curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && DEBIAN_FRONTEND=noninteractive apt-get install -y -q nodejs)" },
      { label: "install opencode", cmd: "npm i -g opencode-ai@latest --no-audit --no-fund 2>&1 | tail -10" },
      { label: "verify binary", cmd: "opencode --version 2>&1 | head -1" },
      { label: "scaffold workdir", cmd: `mkdir -p ${wd} && touch ${envFile} && chmod 600 ${envFile}` },
      { label: "write systemd unit", cmd: `cat > /etc/systemd/system/${unit} <<'EOF'\n${SYSTEMD_TEMPLATE(ctx.name, wd, envFile)}\nEOF\nsystemctl daemon-reload` },
    ], { timeoutMsPerStep: 180_000 });
    const v = await exec(ctx.hostId, "opencode --version 2>/dev/null | head -1", { timeoutMs: 10_000 });
    return { ok: r.ok, log: r.log, version: v.stdout.trim() || undefined };
  },

  async update(ctx) {
    const r = await execScript(ctx.hostId, [
      { label: "update opencode", cmd: "npm i -g opencode-ai@latest --no-audit --no-fund 2>&1 | tail -20" },
      { label: "version", cmd: "opencode --version" },
      { label: "restart unit", cmd: `systemctl is-enabled ${unitName(ctx)} >/dev/null 2>&1 && systemctl restart ${unitName(ctx)} || true` },
    ], { timeoutMsPerStep: 180_000 });
    const v = await exec(ctx.hostId, "opencode --version 2>/dev/null | head -1");
    return { ok: r.ok, log: r.log, version: v.stdout.trim() || undefined };
  },

  async status(ctx) {
    const v = await exec(ctx.hostId, "opencode --version 2>/dev/null | head -1");
    const s = await exec(ctx.hostId, `systemctl is-active ${unitName(ctx)} 2>/dev/null; systemctl show ${unitName(ctx)} -p MainPID --value 2>/dev/null`);
    const lines = s.stdout.trim().split("\n");
    const active = lines[0]?.trim() === "active";
    const pid = parseInt(lines[1] || "0", 10) || undefined;
    return {
      ok: true,
      log: `version: ${v.stdout.trim()}\nunit: ${lines[0]}\npid: ${pid ?? "-"}`,
      version: v.stdout.trim() || undefined,
      running: active,
      pid: active ? pid : undefined,
    };
  },

  async start(ctx) {
    const r = await execScript(ctx.hostId, [
      { label: "enable+start", cmd: `systemctl enable --now ${unitName(ctx)}` },
      { label: "status", cmd: `systemctl is-active ${unitName(ctx)}` },
    ]);
    return { ok: r.ok, log: r.log };
  },

  async stop(ctx) {
    const r = await execScript(ctx.hostId, [
      { label: "stop", cmd: `systemctl stop ${unitName(ctx)}` },
    ]);
    return { ok: r.ok, log: r.log };
  },

  async logs(ctx, lines = 200) {
    const r = await exec(ctx.hostId, `tail -n ${lines} /var/log/agent-${ctx.name}.log 2>/dev/null || journalctl -u ${unitName(ctx)} -n ${lines} --no-pager`, { timeoutMs: 15_000 });
    return { ok: true, log: r.stdout || r.stderr };
  },

  async uninstall(ctx) {
    const wd = workdir(ctx);
    const r = await execScript(ctx.hostId, [
      { label: "stop+disable", cmd: `systemctl disable --now ${unitName(ctx)} 2>/dev/null || true` },
      { label: "rm unit", cmd: `rm -f /etc/systemd/system/${unitName(ctx)} && systemctl daemon-reload` },
      { label: "rm workdir", cmd: `rm -rf ${wd}` },
      { label: "rm log", cmd: `rm -f /var/log/agent-${ctx.name}.log` },
    ], { stopOnFail: false });
    return { ok: r.ok, log: r.log };
  },
};
