import {
  assertIsoRecordedAt,
  assertSafePathSegment,
  assertString,
  isRecord,
  optionalStringArray,
  recordStoreDay,
  validateStringRecord
} from "./chunk-DGXUHMOV.js";
import {
  listJsonFiles,
  readJsonFile
} from "./chunk-LPSF4OQH.js";

// src/utility-telemetry.ts
import path from "path";
import { mkdir, writeFile } from "fs/promises";
function resolveUtilityTelemetryDir(memoryDir, overrideDir) {
  if (typeof overrideDir === "string" && overrideDir.trim().length > 0) {
    return overrideDir.trim();
  }
  return path.join(memoryDir, "state", "utility-telemetry");
}
function assertUtilityScore(value) {
  if (typeof value !== "number" || !Number.isFinite(value)) {
    throw new Error("utilityScore must be a finite number");
  }
  if (value < -1 || value > 1) {
    throw new Error("utilityScore must be between -1 and 1");
  }
  return value;
}
function validateUtilityTelemetryEvent(raw) {
  if (!isRecord(raw)) throw new Error("utility telemetry event must be an object");
  if (raw.schemaVersion !== 1) throw new Error("schemaVersion must be 1");
  const source = assertString(raw.source, "source");
  if (!["cli", "system", "benchmark", "tool_result"].includes(source)) {
    throw new Error("source must be one of cli|system|benchmark|tool_result");
  }
  const target = assertString(raw.target, "target");
  if (!["promotion", "ranking"].includes(target)) {
    throw new Error("target must be one of promotion|ranking");
  }
  const decision = assertString(raw.decision, "decision");
  if (!["promote", "demote", "hold", "boost", "suppress"].includes(decision)) {
    throw new Error("decision must be one of promote|demote|hold|boost|suppress");
  }
  const outcome = assertString(raw.outcome, "outcome");
  if (!["helpful", "neutral", "harmful"].includes(outcome)) {
    throw new Error("outcome must be one of helpful|neutral|harmful");
  }
  return {
    schemaVersion: 1,
    eventId: assertSafePathSegment(assertString(raw.eventId, "eventId"), "eventId"),
    recordedAt: assertIsoRecordedAt(assertString(raw.recordedAt, "recordedAt")),
    sessionKey: assertString(raw.sessionKey, "sessionKey"),
    source,
    target,
    decision,
    outcome,
    utilityScore: assertUtilityScore(raw.utilityScore),
    summary: assertString(raw.summary, "summary"),
    memoryIds: optionalStringArray(raw.memoryIds, "memoryIds"),
    entityRefs: optionalStringArray(raw.entityRefs, "entityRefs"),
    tags: optionalStringArray(raw.tags, "tags"),
    metadata: validateStringRecord(raw.metadata, "metadata")
  };
}
async function recordUtilityTelemetryEvent(options) {
  const rootDir = resolveUtilityTelemetryDir(options.memoryDir, options.utilityTelemetryDir);
  const validated = validateUtilityTelemetryEvent(options.event);
  const day = recordStoreDay(validated.recordedAt);
  const eventsDir = path.join(rootDir, "events", day);
  const filePath = path.join(eventsDir, `${validated.eventId}.json`);
  await mkdir(eventsDir, { recursive: true });
  await writeFile(filePath, JSON.stringify(validated, null, 2), "utf8");
  return filePath;
}
async function readUtilityTelemetryEvents(options) {
  const rootDir = resolveUtilityTelemetryDir(options.memoryDir, options.utilityTelemetryDir);
  const files = await listJsonFiles(path.join(rootDir, "events"));
  const events = [];
  const invalidEvents = [];
  for (const filePath of files) {
    try {
      events.push(validateUtilityTelemetryEvent(await readJsonFile(filePath)));
    } catch (error) {
      invalidEvents.push({
        path: filePath,
        error: error instanceof Error ? error.message : String(error)
      });
    }
  }
  return { files, events, invalidEvents };
}
async function getUtilityTelemetryStatus(options) {
  const rootDir = resolveUtilityTelemetryDir(options.memoryDir, options.utilityTelemetryDir);
  const eventsDir = path.join(rootDir, "events");
  if (!options.enabled) {
    return {
      enabled: false,
      promotionByOutcomeEnabled: options.promotionByOutcomeEnabled === true,
      rootDir,
      eventsDir,
      events: {
        total: 0,
        valid: 0,
        invalid: 0,
        byTarget: {},
        byDecision: {},
        byOutcome: {}
      },
      invalidEvents: []
    };
  }
  const { files, events, invalidEvents } = await readUtilityTelemetryEvents(options);
  events.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));
  const byTarget = {};
  const byDecision = {};
  const byOutcome = {};
  for (const event of events) {
    byTarget[event.target] = (byTarget[event.target] ?? 0) + 1;
    byDecision[event.decision] = (byDecision[event.decision] ?? 0) + 1;
    byOutcome[event.outcome] = (byOutcome[event.outcome] ?? 0) + 1;
  }
  return {
    enabled: true,
    promotionByOutcomeEnabled: options.promotionByOutcomeEnabled === true,
    rootDir,
    eventsDir,
    events: {
      total: files.length,
      valid: events.length,
      invalid: invalidEvents.length,
      byTarget,
      byDecision,
      byOutcome,
      latestEventId: events[0]?.eventId,
      latestRecordedAt: events[0]?.recordedAt,
      latestSessionKey: events[0]?.sessionKey
    },
    latestEvent: events[0],
    invalidEvents
  };
}

export {
  resolveUtilityTelemetryDir,
  validateUtilityTelemetryEvent,
  recordUtilityTelemetryEvent,
  readUtilityTelemetryEvents,
  getUtilityTelemetryStatus
};
//# sourceMappingURL=chunk-3QKK7QOS.js.map