// Generated by tools/experiments/hooks-mgr.
// hooks-mgr-owned: coding-agent-remote-collector/pi
import { spawn } from "node:child_process";

const COLLECTOR = {{json:collector}};
const COLLECTOR_PRIVATE_KEY = {{json:collector_private_key}};
const URL_BASE = {{json:url_base}};
const EVENTS = [
  "tool_call",
  "tool_result",
  "session_start",
  "session_before_switch",
  "session_switch",
  "session_before_branch",
  "session_branch",
  "session_before_compact",
  "session.compacting",
  "session_compact",
  "session_before_tree",
  "session_tree",
  "session_shutdown",
  "before_agent_start",
  "agent_start",
  "agent_end",
  "turn_start",
  "turn_end",
  "context",
  "auto_compaction_start",
  "auto_compaction_end",
  "auto_retry_start",
  "auto_retry_end",
  "ttsr_triggered",
  "todo_reminder",
];

function toJson(value) {
  const seen = new WeakSet();
  return JSON.stringify(value, (_key, item) => {
    if (typeof item === "bigint") return item.toString();
    if (typeof item === "function") return `[Function ${item.name || "anonymous"}]`;
    if (item instanceof Error) {
      return {
        name: item.name,
        message: item.message,
        stack: item.stack,
      };
    }
    if (item instanceof Map) return Object.fromEntries(item);
    if (item instanceof Set) return Array.from(item);
    if (item && typeof item === "object") {
      if (seen.has(item)) return "[Circular]";
      seen.add(item);
    }
    return item;
  });
}

function sessionId(ctx) {
  try {
    return ctx?.sessionManager?.getSessionFile?.() ?? undefined;
  } catch {
    return undefined;
  }
}

function modelSnapshot(ctx) {
  try {
    const model = ctx?.models?.current?.() ?? ctx?.model;
    if (typeof model === "string") return model;
    const provider = model?.provider;
    const id = model?.id;
    if (typeof provider === "string" && typeof id === "string") {
      return `${provider}/${id}`;
    }
    if (typeof id === "string") return id;
    return undefined;
  } catch {
    return undefined;
  }
}

function contextUsageSnapshot(ctx) {
  try {
    return ctx?.getContextUsage?.();
  } catch {
    return undefined;
  }
}

function emit(eventName, event, ctx, contextUsage) {
  const payload = {
    hook_event_name: eventName,
    cwd: ctx?.cwd,
    session_id: sessionId(ctx),
    model: modelSnapshot(ctx),
    context_usage: contextUsage,
    event,
  };
  const child = spawn("python3", [
    COLLECTOR,
    "--url",
    `${URL_BASE}/${eventName}`,
    "--agent",
    "pi",
    "--stdin",
    "--no-env",
    "--best-effort",
    "--timeout",
    "5",
    "--private-key",
    COLLECTOR_PRIVATE_KEY,
  ], {
    detached: true,
    stdio: ["pipe", "ignore", "ignore"],
  });
  child.on("error", () => {});
  child.stdin.on("error", () => {});
  child.stdin.end(toJson(payload));
  child.unref();
}

export default function teamCollector(pi) {
  for (const eventName of EVENTS) {
    pi.on(eventName, (event, ctx) => {
      try {
        const contextUsage = contextUsageSnapshot(ctx);
        if (contextUsage && typeof contextUsage.then === "function") {
          contextUsage.then(
            (resolvedUsage) => {
              try { emit(eventName, event, ctx, resolvedUsage); } catch {}
            },
            () => {
              try { emit(eventName, event, ctx, undefined); } catch {}
            },
          );
          return;
        }
        emit(eventName, event, ctx, contextUsage);
      } catch {
        // Hooks must never block tool usage when the collector, Python, or this
        // generated script has a problem.
      }
    });
  }
}
