import {
  getSession
} from "./chunk-SEGKFEG5.js";
import {
  appendEvent,
  appendEventsBatch,
  listEvents,
  rowToManagedEvent
} from "./chunk-LH3NEWMT.js";
import {
  getAgent
} from "./chunk-LGPJPAHU.js";
import {
  getDb,
  init_client
} from "./chunk-TLEKKGH7.js";

// src/sessions/bus.ts
import { EventEmitter } from "events";
import crypto from "crypto";
init_client();
function emitters() {
  const g = globalThis;
  if (!g.__caBusEmitters) g.__caBusEmitters = /* @__PURE__ */ new Map();
  return g.__caBusEmitters;
}
var webhookCache = /* @__PURE__ */ new Map();
function getWebhookConfig(sessionId) {
  const cached = webhookCache.get(sessionId);
  if (cached) return cached;
  const session = getSession(sessionId);
  if (!session) {
    const entry2 = { webhookUrl: null, webhookEvents: [], webhookSecret: null };
    webhookCache.set(sessionId, entry2);
    return entry2;
  }
  const agent = getAgent(session.agent.id, session.agent.version);
  const ver = getDb().prepare(`SELECT webhook_secret FROM agent_versions WHERE agent_id = ? AND version = ?`).get(session.agent.id, session.agent.version);
  const entry = {
    webhookUrl: agent?.webhook_url ?? null,
    webhookEvents: agent?.webhook_events ?? [],
    webhookSecret: ver?.webhook_secret ?? null
  };
  webhookCache.set(sessionId, entry);
  return entry;
}
function getOrCreateEmitter(sessionId) {
  const reg = emitters();
  let em = reg.get(sessionId);
  if (!em) {
    em = new EventEmitter();
    em.setMaxListeners(0);
    reg.set(sessionId, em);
  }
  return em;
}
function signPayload(secret, timestampMs, payload) {
  const h = crypto.createHmac("sha256", secret);
  h.update(`${timestampMs}.${payload}`);
  return h.digest("hex");
}
function fireWebhook(sessionId, row) {
  try {
    const config = getWebhookConfig(sessionId);
    if (!config.webhookUrl) return;
    if (!config.webhookEvents.includes(row.type)) return;
    const payload = JSON.stringify(rowToManagedEvent(row));
    const headers = {
      "Content-Type": "application/json",
      "User-Agent": "agentstep-webhook/1"
    };
    if (config.webhookSecret) {
      const ts = Date.now();
      headers["X-AgentStep-Timestamp"] = String(ts);
      headers["X-AgentStep-Signature"] = `sha256=${signPayload(config.webhookSecret, ts, payload)}`;
    }
    void fetch(config.webhookUrl, {
      method: "POST",
      headers,
      body: payload,
      signal: AbortSignal.timeout(5e3)
    }).catch((err) => {
      console.warn(`[webhook] POST to ${config.webhookUrl} failed:`, err);
    });
  } catch {
  }
}
function hooks() {
  const g = globalThis;
  if (!g.__caBusAfterCommit) g.__caBusAfterCommit = /* @__PURE__ */ new Set();
  return g.__caBusAfterCommit;
}
function onAfterCommit(fn) {
  hooks().add(fn);
  return () => hooks().delete(fn);
}
function fireHooks(sessionId, row) {
  for (const fn of hooks()) {
    try {
      fn(sessionId, row);
    } catch (err) {
      console.warn(`[bus] after-commit hook failed:`, err);
    }
  }
}
function installPayloadRedactor(fn) {
  const g = globalThis;
  g.__caBusRedactor = fn ?? void 0;
}
function redact(input) {
  const g = globalThis;
  const fn = g.__caBusRedactor;
  return fn ? fn(input) : input;
}
function appendEvent2(sessionId, input) {
  const row = appendEvent(sessionId, redact(input));
  getOrCreateEmitter(sessionId).emit("event", row);
  fireWebhook(sessionId, row);
  fireHooks(sessionId, row);
  return row;
}
function appendEventsBatch2(sessionId, inputs) {
  const rows = appendEventsBatch(sessionId, inputs.map(redact));
  const em = getOrCreateEmitter(sessionId);
  for (const row of rows) {
    em.emit("event", row);
    fireWebhook(sessionId, row);
    fireHooks(sessionId, row);
  }
  return rows;
}
function subscribe(sessionId, fromSeq, onEvent) {
  const em = getOrCreateEmitter(sessionId);
  let lastDeliveredSeq = fromSeq;
  const backlog = listEvents(sessionId, { limit: 500, order: "asc", afterSeq: fromSeq });
  for (const row of backlog) {
    onEvent(rowToManagedEvent(row));
    if (row.seq > lastDeliveredSeq) lastDeliveredSeq = row.seq;
  }
  const handler = (row) => {
    if (row.seq <= lastDeliveredSeq) return;
    onEvent(rowToManagedEvent(row));
    lastDeliveredSeq = row.seq;
  };
  em.on("event", handler);
  return {
    unsubscribe() {
      em.off("event", handler);
    }
  };
}
function dropEmitter(sessionId) {
  const reg = emitters();
  const em = reg.get(sessionId);
  if (em) em.removeAllListeners();
  reg.delete(sessionId);
  webhookCache.delete(sessionId);
}

export {
  onAfterCommit,
  installPayloadRedactor,
  appendEvent2 as appendEvent,
  appendEventsBatch2 as appendEventsBatch,
  subscribe,
  dropEmitter
};
