#!/usr/bin/env node
/* global console, process */
// SDK 0.2.113+ ships the Claude Code runtime as a per-platform native binary
// via optional dependencies (`@anthropic-ai/claude-agent-sdk-<platform>-<arch>`).
// When users install duoduo with `--omit=optional` / `NPM_CONFIG_OPTIONAL=false`
// or on an unsupported platform/arch combo, the binary is missing and the
// failure only surfaces on the first `query()` call deep inside a live session.
//
// This preflight catches that case at install time: try to resolve the SDK,
// locate the platform binary it would spawn, and print a clear actionable
// warning if something is off. We warn rather than error-exit so that
// development installs (where the SDK may not yet be linked) don't break;
// the daemon runs the same check at boot and fails fast there.
import { createRequire } from "node:module";
import { stat } from "node:fs/promises";

const require = createRequire(import.meta.url);

function platformPackageName() {
  const { platform, arch } = process;
  const key = `${platform}-${arch}`;
  const supported = new Set([
    "darwin-arm64",
    "darwin-x64",
    "linux-x64",
    "linux-arm64",
    "win32-x64",
    "win32-arm64"
  ]);
  if (!supported.has(key)) return null;
  // musl detection: node reports `linux` but the SDK ships separate
  // `-musl` packages. A quick heuristic via `process.report` would be
  // nice but isn't reliable; instead we try the glibc variant first
  // and fall back to musl if that package isn't resolvable.
  return `@anthropic-ai/claude-agent-sdk-${platform}-${arch}`;
}

function tryResolveBinary(pkg) {
  try {
    return require.resolve(`${pkg}/claude`);
  } catch {
    return null;
  }
}

async function binaryIsExecutable(path) {
  try {
    const s = await stat(path);
    return s.isFile();
  } catch {
    return false;
  }
}

async function main() {
  let sdkResolved = false;
  try {
    require.resolve("@anthropic-ai/claude-agent-sdk");
    sdkResolved = true;
  } catch {
    // Dev-only install (no runtime dep); silently skip preflight.
    return;
  }
  if (!sdkResolved) return;

  const pkg = platformPackageName();
  if (!pkg) {
    console.warn(
      `[duoduo] WARN: platform ${process.platform}-${process.arch} is not in the ` +
        "list of @anthropic-ai/claude-agent-sdk native binary packages " +
        "(darwin-arm64, darwin-x64, linux-x64, linux-arm64, win32-x64, win32-arm64). " +
        "The daemon will fail to start. If you are on linux-musl, install the " +
        "matching -musl optional package manually."
    );
    return;
  }

  // Try primary (glibc) package; fall back to -musl on linux.
  let binPath = tryResolveBinary(pkg);
  if (!binPath && process.platform === "linux") {
    binPath = tryResolveBinary(`${pkg}-musl`);
  }

  if (!binPath) {
    console.warn(
      `[duoduo] WARN: native Claude Code binary for ${process.platform}-${process.arch} ` +
        "was not found in node_modules. This usually means the install ran with " +
        "`--omit=optional` or `NPM_CONFIG_OPTIONAL=false`. The daemon will fail " +
        "to spawn agent subprocesses. Reinstall without the optional-omit flag, " +
        `or manually install the optional package \`${pkg}\` (or its \`-musl\` ` +
        "variant on Alpine/musl systems)."
    );
    return;
  }

  if (!(await binaryIsExecutable(binPath))) {
    console.warn(
      `[duoduo] WARN: found platform binary at ${binPath} but it is not a regular ` +
        "file. The daemon will likely fail to spawn the agent subprocess."
    );
  }
}

main().catch((err) => {
  // Never fail the install — the daemon preflight repeats this check and
  // can produce a richer error once the runtime knows the install context.
  console.warn(`[duoduo] postinstall preflight skipped: ${err?.message ?? err}`);
});
