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

// src/abstraction-nodes.ts
import path from "path";
import { mkdir, writeFile } from "fs/promises";
function validateKind(raw) {
  const value = assertString(raw, "kind");
  if (!["episode", "topic", "project", "workflow", "constraint"].includes(value)) {
    throw new Error("kind must be one of episode|topic|project|workflow|constraint");
  }
  return value;
}
function validateLevel(raw) {
  const value = assertString(raw, "abstractionLevel");
  if (!["micro", "meso", "macro"].includes(value)) {
    throw new Error("abstractionLevel must be one of micro|meso|macro");
  }
  return value;
}
function resolveAbstractionNodeStoreDir(memoryDir, overrideDir) {
  if (typeof overrideDir === "string" && overrideDir.trim().length > 0) {
    return overrideDir.trim();
  }
  return path.join(memoryDir, "state", "abstraction-nodes");
}
function validateAbstractionNode(raw) {
  if (!isRecord(raw)) throw new Error("abstraction node must be an object");
  if (raw.schemaVersion !== 1) throw new Error("schemaVersion must be 1");
  return {
    schemaVersion: 1,
    nodeId: assertSafePathSegment(assertString(raw.nodeId, "nodeId"), "nodeId"),
    recordedAt: assertIsoRecordedAt(assertString(raw.recordedAt, "recordedAt")),
    sessionKey: assertString(raw.sessionKey, "sessionKey"),
    kind: validateKind(raw.kind),
    abstractionLevel: validateLevel(raw.abstractionLevel),
    title: assertString(raw.title, "title"),
    summary: assertString(raw.summary, "summary"),
    sourceMemoryIds: optionalStringArray(raw.sourceMemoryIds, "sourceMemoryIds"),
    entityRefs: optionalStringArray(raw.entityRefs, "entityRefs"),
    tags: optionalStringArray(raw.tags, "tags"),
    metadata: validateStringRecord(raw.metadata, "metadata")
  };
}
async function recordAbstractionNode(options) {
  const rootDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);
  const validated = validateAbstractionNode(options.node);
  const day = recordStoreDay(validated.recordedAt);
  const nodesDir = path.join(rootDir, "nodes", day);
  const filePath = path.join(nodesDir, `${validated.nodeId}.json`);
  await mkdir(nodesDir, { recursive: true });
  await writeFile(filePath, JSON.stringify(validated, null, 2), "utf8");
  return filePath;
}
async function getAbstractionNodeStoreStatus(options) {
  const rootDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);
  const nodesDir = path.join(rootDir, "nodes");
  const files = await listJsonFiles(nodesDir);
  const nodes = [];
  const invalidNodes = [];
  for (const filePath of files) {
    try {
      nodes.push(validateAbstractionNode(await readJsonFile(filePath)));
    } catch (error) {
      invalidNodes.push({
        path: filePath,
        error: error instanceof Error ? error.message : String(error)
      });
    }
  }
  nodes.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));
  const byKind = {};
  const byLevel = {};
  for (const node of nodes) {
    byKind[node.kind] = (byKind[node.kind] ?? 0) + 1;
    byLevel[node.abstractionLevel] = (byLevel[node.abstractionLevel] ?? 0) + 1;
  }
  return {
    enabled: options.enabled,
    anchorsEnabled: options.anchorsEnabled,
    rootDir,
    nodesDir,
    nodes: {
      total: files.length,
      valid: nodes.length,
      invalid: invalidNodes.length,
      byKind,
      byLevel,
      latestNodeId: nodes[0]?.nodeId,
      latestRecordedAt: nodes[0]?.recordedAt,
      latestSessionKey: nodes[0]?.sessionKey
    },
    latestNode: nodes[0],
    invalidNodes
  };
}

export {
  resolveAbstractionNodeStoreDir,
  validateAbstractionNode,
  recordAbstractionNode,
  getAbstractionNodeStoreStatus
};
//# sourceMappingURL=chunk-NGAVDO7E.js.map