import {
  MEMORY_FILE_NAME,
  loadMemory
} from "./chunk-DFR4DJBM.js";
import {
  LUMENFLOW_MEMORY_PATHS
} from "./chunk-4N74J3UT.js";
import {
  MS_PER_DAY,
  MS_PER_HOUR
} from "./chunk-V6OJGLBA.js";
import {
  ErrorCodes,
  createError
} from "./chunk-RXRKBBSM.js";

// ../memory/dist/mem-delete-core.js
import fs from "fs/promises";
import path from "path";
var DURATION_MULTIPLIERS = {
  h: MS_PER_HOUR,
  d: MS_PER_DAY,
  w: 7 * MS_PER_DAY
};
function parseDuration(duration) {
  const durationRegex = /^(\d+)([hdw])$/;
  const match = durationRegex.exec(duration);
  if (!match || match.length < 3) {
    throw createError(ErrorCodes.INVALID_DURATION, `Invalid duration format: ${duration}. Use format like '7d', '24h', '2w'`);
  }
  const valueStr = match[1];
  const unit = match[2];
  if (!valueStr || !unit) {
    throw createError(ErrorCodes.INVALID_DURATION, `Invalid duration format: ${duration}. Use format like '7d', '24h', '2w'`);
  }
  const value = parseInt(valueStr, 10);
  const multiplier = DURATION_MULTIPLIERS[unit];
  if (!multiplier) {
    throw createError(ErrorCodes.INVALID_DURATION, `Unknown duration unit: ${unit}`);
  }
  return value * multiplier;
}
function matchesTag(node, tag) {
  return Array.isArray(node.tags) && node.tags.includes(tag);
}
function isOlderThan(node, durationMs, referenceDate) {
  const nodeDate = new Date(node.created_at);
  const cutoffDate = new Date(referenceDate.getTime() - durationMs);
  return nodeDate < cutoffDate;
}
function isAlreadyDeleted(node) {
  return node.metadata?.status === "deleted";
}
function markAsDeleted(node) {
  return {
    ...node,
    metadata: {
      ...node.metadata,
      status: "deleted",
      deleted_at: (/* @__PURE__ */ new Date()).toISOString()
    }
  };
}
function processNodeIdsFilter(nodeIds, nodeMap, toDeleteSet, errors) {
  for (const nodeId of nodeIds) {
    const node = nodeMap.get(nodeId);
    if (node) {
      toDeleteSet.add(nodeId);
    } else {
      errors.push(`Node not found: ${nodeId}`);
    }
  }
}
function processTagFilter(nodes, tag, toDeleteSet) {
  for (const node of nodes) {
    if (matchesTag(node, tag)) {
      toDeleteSet.add(node.id);
    }
  }
}
function processOlderThanFilter(nodes, olderThan, referenceDate, tag, hasNodeIds, toDeleteSet) {
  const durationMs = parseDuration(olderThan);
  for (const node of nodes) {
    const nodeIsOld = isOlderThan(node, durationMs, referenceDate);
    if (tag) {
      const shouldInclude = nodeIsOld && matchesTag(node, tag);
      if (shouldInclude) {
        toDeleteSet.add(node.id);
      } else {
        toDeleteSet.delete(node.id);
      }
    } else if (!hasNodeIds && nodeIsOld) {
      toDeleteSet.add(node.id);
    }
  }
}
function findNodesToDelete(nodes, options) {
  const { nodeIds, tag, olderThan, referenceDate = /* @__PURE__ */ new Date() } = options;
  const errors = [];
  const toDeleteSet = /* @__PURE__ */ new Set();
  const nodeMap = /* @__PURE__ */ new Map();
  for (const node of nodes) {
    nodeMap.set(node.id, node);
  }
  if (nodeIds && nodeIds.length > 0) {
    processNodeIdsFilter(nodeIds, nodeMap, toDeleteSet, errors);
  }
  if (tag) {
    processTagFilter(nodes, tag, toDeleteSet);
  }
  if (olderThan) {
    const hasNodeIds = Boolean(nodeIds && nodeIds.length > 0);
    processOlderThanFilter(nodes, olderThan, referenceDate, tag, hasNodeIds, toDeleteSet);
  }
  const toDelete = [];
  for (const nodeId of toDeleteSet) {
    const node = nodeMap.get(nodeId);
    if (node) {
      toDelete.push(node);
    }
  }
  return { toDelete, errors };
}
async function writeUpdatedNodes(baseDir, nodes) {
  const filePath = path.join(baseDir, MEMORY_FILE_NAME);
  const content = nodes.map((node) => JSON.stringify(node)).join("\n") + "\n";
  await fs.writeFile(filePath, content, "utf-8");
}
async function deleteMemoryNodes(baseDir, options) {
  const { nodeIds, tag, olderThan, dryRun = false } = options;
  if ((!nodeIds || nodeIds.length === 0) && !tag && !olderThan) {
    return {
      success: false,
      deletedCount: 0,
      deletedIds: [],
      skippedIds: [],
      dryRun,
      errors: ["At least one filter (nodeIds, tag, or olderThan) is required"]
    };
  }
  const memoryDir = path.join(baseDir, LUMENFLOW_MEMORY_PATHS.MEMORY_DIR);
  let memory;
  try {
    memory = await loadMemory(memoryDir, { includeArchived: true });
  } catch (err) {
    const errMsg = err instanceof Error ? err.message : String(err);
    return {
      success: false,
      deletedCount: 0,
      deletedIds: [],
      skippedIds: [],
      dryRun,
      errors: [`Failed to load memory: ${errMsg}`]
    };
  }
  const { toDelete, errors } = findNodesToDelete(memory.nodes, options);
  const deletedIds = [];
  const skippedIds = [];
  const nodesToUpdate = [];
  for (const node of toDelete) {
    if (isAlreadyDeleted(node)) {
      skippedIds.push(node.id);
      errors.push(`Node already deleted: ${node.id}`);
    } else {
      deletedIds.push(node.id);
      nodesToUpdate.push(node);
    }
  }
  if (!dryRun && nodesToUpdate.length > 0) {
    const deletedIdSet = new Set(deletedIds);
    const updatedNodes = memory.nodes.map((node) => {
      if (deletedIdSet.has(node.id)) {
        return markAsDeleted(node);
      }
      return node;
    });
    await writeUpdatedNodes(memoryDir, updatedNodes);
  }
  const hasNotFoundErrors = errors.some((e) => e.startsWith("Node not found:"));
  const allNodesHandled = deletedIds.length > 0 || skippedIds.length > 0;
  const success = !hasNotFoundErrors || allNodesHandled;
  return {
    success,
    deletedCount: deletedIds.length,
    deletedIds,
    skippedIds,
    dryRun,
    errors
  };
}

export {
  deleteMemoryNodes
};
