import {
  isRecallDisclosure
} from "./chunk-43EKP2UK.js";

// src/recall-xray.ts
import { randomUUID } from "crypto";
function estimateRecallTokens(text) {
  if (typeof text !== "string" || text.length === 0) return 0;
  return Math.ceil(text.length / 4);
}
var RECALL_XRAY_SERVED_BY_VALUES = [
  "direct-answer",
  "hybrid",
  "graph",
  "recent-scan",
  "procedural",
  "review-context"
];
function isRecallXrayServedBy(value) {
  return typeof value === "string" && RECALL_XRAY_SERVED_BY_VALUES.includes(value);
}
function buildXraySnapshot(input) {
  const now = input.now ?? Date.now;
  const snapshotIdGenerator = input.snapshotIdGenerator ?? randomUUID;
  const results = Array.isArray(input.results) ? input.results.map(cloneResult) : [];
  const filters = Array.isArray(input.filters) ? input.filters.map(cloneFilter) : [];
  const budgetChars = nonNegativeInt(input.budget?.chars);
  const budgetUsed = nonNegativeInt(input.budget?.used);
  const tierExplain = input.tierExplain && typeof input.tierExplain === "object" ? cloneTierExplain(input.tierExplain) : null;
  let peerProfileInjection;
  if (input.peerProfileInjection && typeof input.peerProfileInjection === "object") {
    const raw = input.peerProfileInjection;
    const peerId = nonEmptyString(raw.peerId);
    if (peerId !== void 0) {
      peerProfileInjection = {
        peerId,
        fieldsInjected: nonNegativeInt(raw.fieldsInjected)
      };
    }
  } else if (input.peerProfileInjection === null) {
    peerProfileInjection = null;
  }
  const out = {
    schemaVersion: "1",
    query: typeof input.query === "string" ? input.query : "",
    snapshotId: snapshotIdGenerator(),
    capturedAt: now(),
    tierExplain,
    results,
    filters,
    budget: { chars: budgetChars, used: budgetUsed },
    sessionKey: nonEmptyString(input.sessionKey),
    namespace: nonEmptyString(input.namespace),
    traceId: nonEmptyString(input.traceId)
  };
  if (peerProfileInjection !== void 0) {
    out.peerProfileInjection = peerProfileInjection;
  }
  return out;
}
var RecallXrayBuilder = class {
  query;
  sessionKey;
  namespace;
  traceId;
  tierExplain = null;
  results = [];
  filters = [];
  budgetChars = 0;
  budgetUsed = 0;
  peerProfileInjection;
  constructor(opts) {
    this.query = typeof opts.query === "string" ? opts.query : "";
    this.sessionKey = nonEmptyString(opts.sessionKey);
    this.namespace = nonEmptyString(opts.namespace);
    this.traceId = nonEmptyString(opts.traceId);
  }
  setNamespace(namespace) {
    this.namespace = nonEmptyString(namespace);
  }
  setTraceId(traceId) {
    this.traceId = nonEmptyString(traceId);
  }
  setTierExplain(tierExplain) {
    this.tierExplain = tierExplain && typeof tierExplain === "object" ? cloneTierExplain(tierExplain) : null;
  }
  setBudget(budget) {
    this.budgetChars = nonNegativeInt(budget.chars);
    this.budgetUsed = nonNegativeInt(budget.used);
  }
  /**
   * Record peer-profile injection metadata for this recall snapshot
   * (issue #679 completion). Pass `null` to explicitly record that no
   * injection happened (feature enabled but no peer / no profile fields).
   */
  setPeerProfileInjection(injection) {
    this.peerProfileInjection = injection;
  }
  recordResult(result) {
    this.results.push(cloneResult(result));
  }
  recordFilter(filter) {
    this.filters.push(cloneFilter(filter));
  }
  build(opts = {}) {
    return buildXraySnapshot({
      query: this.query,
      tierExplain: this.tierExplain,
      results: this.results,
      filters: this.filters,
      budget: { chars: this.budgetChars, used: this.budgetUsed },
      sessionKey: this.sessionKey,
      namespace: this.namespace,
      traceId: this.traceId,
      peerProfileInjection: this.peerProfileInjection,
      now: opts.now,
      snapshotIdGenerator: opts.snapshotIdGenerator
    });
  }
};
function cloneResult(result) {
  if (!result || typeof result !== "object") {
    throw new TypeError("RecallXrayResult must be an object");
  }
  if (!isRecallXrayServedBy(result.servedBy)) {
    throw new TypeError(
      `RecallXrayResult.servedBy must be one of ${RECALL_XRAY_SERVED_BY_VALUES.join(
        ", "
      )}; got ${JSON.stringify(result.servedBy)}`
    );
  }
  const memoryId = typeof result.memoryId === "string" ? result.memoryId : "";
  const path = typeof result.path === "string" ? result.path : "";
  const admittedBy = Array.isArray(result.admittedBy) ? result.admittedBy.filter((x) => typeof x === "string") : [];
  const graphPath = Array.isArray(result.graphPath) ? result.graphPath.filter((x) => typeof x === "string") : void 0;
  let graphEdgeConfidences;
  if (Array.isArray(result.graphEdgeConfidences) && graphPath && graphPath.length > 1) {
    const expected = graphPath.length - 1;
    const raw = result.graphEdgeConfidences;
    if (raw.length === expected) {
      const cleaned = [];
      let allFinite = true;
      for (const value of raw) {
        if (typeof value !== "number" || !Number.isFinite(value)) {
          allFinite = false;
          break;
        }
        cleaned.push(Math.min(1, Math.max(0, value)));
      }
      if (allFinite) {
        graphEdgeConfidences = cleaned;
      }
    }
  }
  const auditEntryId = nonEmptyString(result.auditEntryId);
  const rejectedBy = nonEmptyString(result.rejectedBy);
  const scoreDecomposition = cloneScoreDecomposition(result.scoreDecomposition);
  const out = {
    memoryId,
    path,
    servedBy: result.servedBy,
    scoreDecomposition,
    admittedBy
  };
  if (graphPath !== void 0) out.graphPath = graphPath;
  if (graphEdgeConfidences !== void 0) {
    out.graphEdgeConfidences = graphEdgeConfidences;
  }
  if (auditEntryId !== void 0) out.auditEntryId = auditEntryId;
  if (rejectedBy !== void 0) out.rejectedBy = rejectedBy;
  if (isRecallDisclosure(result.disclosure)) {
    out.disclosure = result.disclosure;
  }
  if (typeof result.estimatedTokens === "number" && Number.isFinite(result.estimatedTokens) && result.estimatedTokens >= 0) {
    out.estimatedTokens = Math.floor(result.estimatedTokens);
  }
  if (Array.isArray(result.tags)) {
    const cleanedTags = result.tags.filter((t) => typeof t === "string").map((t) => t.trim()).filter((t) => t.length > 0);
    if (cleanedTags.length > 0) {
      out.tags = cleanedTags;
    }
  }
  return out;
}
function summarizeDisclosureTokens(results) {
  const summary = {
    chunk: { count: 0, estimatedTokens: 0 },
    section: { count: 0, estimatedTokens: 0 },
    raw: { count: 0, estimatedTokens: 0 },
    unspecified: { count: 0, estimatedTokens: 0 }
  };
  for (const result of results) {
    const tokens = typeof result.estimatedTokens === "number" && Number.isFinite(result.estimatedTokens) && result.estimatedTokens >= 0 ? Math.floor(result.estimatedTokens) : 0;
    const bucket = isRecallDisclosure(result.disclosure) ? result.disclosure : "unspecified";
    summary[bucket].count += 1;
    summary[bucket].estimatedTokens += tokens;
  }
  return summary;
}
function cloneFilter(filter) {
  if (!filter || typeof filter !== "object") {
    throw new TypeError("RecallFilterTrace must be an object");
  }
  const out = {
    name: typeof filter.name === "string" ? filter.name : "",
    considered: nonNegativeInt(filter.considered),
    admitted: nonNegativeInt(filter.admitted)
  };
  const reason = nonEmptyString(filter.reason);
  if (reason !== void 0) out.reason = reason;
  return out;
}
function cloneScoreDecomposition(value) {
  if (!value || typeof value !== "object") {
    return { final: 0 };
  }
  const out = {
    final: finiteNumber(value.final) ?? 0
  };
  const vector = finiteNumber(value.vector);
  if (vector !== void 0) out.vector = vector;
  const bm25 = finiteNumber(value.bm25);
  if (bm25 !== void 0) out.bm25 = bm25;
  const importance = finiteNumber(value.importance);
  if (importance !== void 0) out.importance = importance;
  const mmrPenalty = finiteNumber(value.mmrPenalty);
  if (mmrPenalty !== void 0) out.mmrPenalty = mmrPenalty;
  const tierPrior = finiteNumber(value.tierPrior);
  if (tierPrior !== void 0) out.tierPrior = tierPrior;
  const reinforcementBoost = finiteNumber(value.reinforcementBoost);
  if (reinforcementBoost !== void 0 && reinforcementBoost > 0) {
    out.reinforcementBoost = reinforcementBoost;
  }
  return out;
}
function cloneTierExplain(tierExplain) {
  return structuredClone(tierExplain);
}
function nonNegativeInt(value) {
  if (typeof value !== "number" || !Number.isFinite(value)) return 0;
  if (value <= 0) return 0;
  return Math.floor(value);
}
function finiteNumber(value) {
  if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
  return value;
}
function nonEmptyString(value) {
  if (typeof value !== "string") return void 0;
  const trimmed = value.trim();
  if (trimmed.length === 0) return void 0;
  return trimmed;
}

export {
  estimateRecallTokens,
  RECALL_XRAY_SERVED_BY_VALUES,
  isRecallXrayServedBy,
  buildXraySnapshot,
  RecallXrayBuilder,
  summarizeDisclosureTokens
};
//# sourceMappingURL=chunk-USFPPRAF.js.map