import {
  init_ids,
  newId
} from "./chunk-F4WUVOLE.js";
import {
  init_clock,
  nowMs,
  toIso
} from "./chunk-HFDLUBWN.js";
import {
  getDrizzle,
  init_drizzle
} from "./chunk-RII4M3J2.js";
import {
  schema_exports
} from "./chunk-DDJOPRB7.js";
import {
  getDb,
  init_client
} from "./chunk-TLEKKGH7.js";

// src/db/events.ts
init_client();
init_drizzle();
init_ids();
init_clock();
import { eq, and, gt, asc, desc, isNull } from "drizzle-orm";
function appendEvent(sessionId, input) {
  const db = getDb();
  return db.transaction(() => {
    if (input.idempotencyKey) {
      const dupe = db.prepare(
        `SELECT * FROM events WHERE session_id = ? AND idempotency_key = ?`
      ).get(sessionId, input.idempotencyKey);
      if (dupe) return dupe;
    }
    const row = db.prepare(
      `SELECT last_seq FROM sessions WHERE id = ?`
    ).get(sessionId);
    if (!row) throw new Error(`session not found: ${sessionId}`);
    const seq = row.last_seq + 1;
    const id = newId("evt");
    const receivedAt = nowMs();
    db.prepare(
      `INSERT INTO events (
         id, session_id, seq, type, payload_json,
         processed_at, received_at, origin, idempotency_key,
         trace_id, span_id, parent_span_id
       ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
    ).run(
      id,
      sessionId,
      seq,
      input.type,
      JSON.stringify(input.payload),
      input.processedAt ?? null,
      receivedAt,
      input.origin,
      input.idempotencyKey ?? null,
      input.traceId ?? null,
      input.spanId ?? null,
      input.parentSpanId ?? null
    );
    db.prepare(`UPDATE sessions SET last_seq = ?, updated_at = ? WHERE id = ?`).run(
      seq,
      receivedAt,
      sessionId
    );
    return {
      id,
      session_id: sessionId,
      seq,
      type: input.type,
      payload_json: JSON.stringify(input.payload),
      processed_at: input.processedAt ?? null,
      received_at: receivedAt,
      origin: input.origin,
      idempotency_key: input.idempotencyKey ?? null,
      trace_id: input.traceId ?? null,
      span_id: input.spanId ?? null,
      parent_span_id: input.parentSpanId ?? null
    };
  })();
}
function appendEventsBatch(sessionId, inputs) {
  const db = getDb();
  return db.transaction(() => {
    const rows = [];
    const cur = db.prepare(`SELECT last_seq FROM sessions WHERE id = ?`).get(sessionId);
    if (!cur) throw new Error(`session not found: ${sessionId}`);
    let seq = cur.last_seq;
    const dupeStmt = db.prepare(
      `SELECT * FROM events WHERE session_id = ? AND idempotency_key = ?`
    );
    const insertStmt = db.prepare(
      `INSERT INTO events (
         id, session_id, seq, type, payload_json,
         processed_at, received_at, origin, idempotency_key,
         trace_id, span_id, parent_span_id
       ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
    );
    for (const input of inputs) {
      if (input.idempotencyKey) {
        const dupe = dupeStmt.get(sessionId, input.idempotencyKey);
        if (dupe) {
          rows.push(dupe);
          continue;
        }
      }
      seq += 1;
      const id = newId("evt");
      const receivedAt = nowMs();
      insertStmt.run(
        id,
        sessionId,
        seq,
        input.type,
        JSON.stringify(input.payload),
        input.processedAt ?? null,
        receivedAt,
        input.origin,
        input.idempotencyKey ?? null,
        input.traceId ?? null,
        input.spanId ?? null,
        input.parentSpanId ?? null
      );
      rows.push({
        id,
        session_id: sessionId,
        seq,
        type: input.type,
        payload_json: JSON.stringify(input.payload),
        processed_at: input.processedAt ?? null,
        received_at: receivedAt,
        origin: input.origin,
        idempotency_key: input.idempotencyKey ?? null,
        trace_id: input.traceId ?? null,
        span_id: input.spanId ?? null,
        parent_span_id: input.parentSpanId ?? null
      });
    }
    if (seq !== cur.last_seq) {
      db.prepare(`UPDATE sessions SET last_seq = ?, updated_at = ? WHERE id = ?`).run(
        seq,
        nowMs(),
        sessionId
      );
    }
    return rows;
  })();
}
function markUserEventProcessed(eventId, when) {
  const db = getDrizzle();
  db.update(schema_exports.events).set({ processed_at: when }).where(eq(schema_exports.events.id, eventId)).run();
}
function listEvents(sessionId, opts) {
  const db = getDrizzle();
  const limit = Math.min(Math.max(opts.limit ?? 50, 1), 500);
  const orderDir = opts.order === "desc" ? "desc" : "asc";
  const afterSeq = opts.afterSeq ?? 0;
  const orderClause = orderDir === "desc" ? desc(schema_exports.events.seq) : asc(schema_exports.events.seq);
  return db.select().from(schema_exports.events).where(
    and(
      eq(schema_exports.events.session_id, sessionId),
      gt(schema_exports.events.seq, afterSeq)
    )
  ).orderBy(orderClause).limit(limit).all();
}
function getLastUnprocessedUserMessage(sessionId) {
  const db = getDrizzle();
  return db.select().from(schema_exports.events).where(
    and(
      eq(schema_exports.events.session_id, sessionId),
      eq(schema_exports.events.type, "user.message"),
      isNull(schema_exports.events.processed_at)
    )
  ).orderBy(desc(schema_exports.events.seq)).limit(1).get() ?? null;
}
function listEventsByTrace(traceId, limit = 2e3) {
  const db = getDrizzle();
  return db.select().from(schema_exports.events).where(eq(schema_exports.events.trace_id, traceId)).orderBy(
    asc(schema_exports.events.received_at),
    asc(schema_exports.events.session_id),
    asc(schema_exports.events.seq)
  ).limit(Math.min(Math.max(limit, 1), 1e4)).all();
}
function rowToManagedEvent(row) {
  const { type: _rawType, ...payload } = JSON.parse(row.payload_json);
  const base = {
    id: row.id,
    seq: row.seq,
    session_id: row.session_id,
    type: row.type,
    processed_at: row.processed_at != null ? toIso(row.processed_at) : null,
    ...payload
  };
  if (row.trace_id != null) base.trace_id = row.trace_id;
  if (row.span_id != null) base.span_id = row.span_id;
  if (row.parent_span_id != null) base.parent_span_id = row.parent_span_id;
  return base;
}

export {
  appendEvent,
  appendEventsBatch,
  markUserEventProcessed,
  listEvents,
  getLastUnprocessedUserMessage,
  listEventsByTrace,
  rowToManagedEvent
};
