"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadSharedReminders = loadSharedReminders;
exports.replaceSharedReminders = replaceSharedReminders;
exports.mutateSharedReminders = mutateSharedReminders;
const time_1 = require("@longrun-ai/kernel/utils/time");
const node_crypto_1 = require("node:crypto");
const fs = __importStar(require("node:fs/promises"));
const path = __importStar(require("node:path"));
const zlib_1 = require("zlib");
const async_fifo_mutex_1 = require("./runtime/async-fifo-mutex");
const tool_1 = require("./tool");
const registry_1 = require("./tools/registry");
const sharedReminderLocks = new Map();
function getSharedReminderTargetKey(target) {
    switch (target.kind) {
        case 'agent':
            return `agent:${target.agentId}`;
        case 'task':
            return `task:${target.agentId}:${target.taskDocPath}`;
    }
    const _exhaustive = target;
    return _exhaustive;
}
function getSharedReminderLock(target) {
    const key = getSharedReminderTargetKey(target);
    const existing = sharedReminderLocks.get(key);
    if (existing)
        return existing;
    const created = new async_fifo_mutex_1.AsyncFifoMutex();
    sharedReminderLocks.set(key, created);
    return created;
}
function clearSharedReminderLockIfIdle(target, lock) {
    const key = getSharedReminderTargetKey(target);
    if (sharedReminderLocks.get(key) === lock && !lock.isLocked()) {
        sharedReminderLocks.delete(key);
    }
}
function getTaskDocPathStorageKey(taskDocPath) {
    const normalized = taskDocPath.trim().replace(/\\/g, '/').replace(/\/+$/g, '');
    if (normalized === '') {
        throw new Error('task-scoped reminders require a non-empty taskDocPath');
    }
    const checksum = (0, zlib_1.crc32)(normalized) >>> 0;
    return `crc32-${checksum.toString(16).padStart(8, '0')}`;
}
function getSharedReminderDirPath(target) {
    switch (target.kind) {
        case 'agent':
            return path.resolve(process.cwd(), '.dialogs', 'reminders', 'agents', target.agentId);
        case 'task':
            return path.resolve(process.cwd(), '.dialogs', 'reminders', 'agent_tasks', target.agentId, getTaskDocPathStorageKey(target.taskDocPath));
    }
    const _exhaustive = target;
    return _exhaustive;
}
function ensureReminderIdPathSegment(reminderId) {
    if (!/^[A-Za-z0-9_-]+$/.test(reminderId)) {
        throw new Error(`Unsafe reminder_id for shared reminder storage: ${reminderId}`);
    }
    return reminderId;
}
function getSharedReminderFilePath(target, reminderId) {
    return path.join(getSharedReminderDirPath(target), `${ensureReminderIdPathSegment(reminderId)}.json`);
}
function serializeReminder(reminder) {
    return {
        id: reminder.id,
        content: reminder.content,
        // Persist only the stable owner route key. The framework must not peek into owner
        // metadata to "rediscover" which owner should handle this reminder.
        ownerName: reminder.owner?.name,
        meta: reminder.meta,
        echoback: reminder.echoback,
        scope: reminder.scope,
        renderMode: reminder.renderMode,
        createdAt: reminder.createdAt ?? (0, time_1.formatUnifiedTimestamp)(new Date()),
        priority: reminder.priority ?? 'medium',
    };
}
function materializeStoredReminder(snapshot) {
    const ownerName = typeof snapshot.ownerName === 'string' ? snapshot.ownerName : undefined;
    // Unknown owners are preserved as ownerless opaque reminders rather than guessed from meta.
    const owner = ownerName ? (0, registry_1.getReminderOwner)(ownerName) : undefined;
    return (0, tool_1.materializeReminder)({
        id: snapshot.id,
        content: snapshot.content,
        owner,
        meta: snapshot.meta,
        echoback: snapshot.echoback,
        scope: snapshot.scope ?? 'agent',
        renderMode: snapshot.renderMode ?? 'markdown',
        createdAt: snapshot.createdAt,
        priority: snapshot.priority,
    });
}
function cloneReminderList(reminders) {
    return reminders.map((reminder) => (0, tool_1.cloneReminder)(reminder));
}
async function writeReminderSnapshotFile(filePath, snapshot) {
    const json = JSON.stringify(snapshot, null, 2);
    const tempFile = `${filePath}.${process.pid}.${(0, node_crypto_1.randomUUID)()}.tmp`;
    await fs.writeFile(tempFile, json, 'utf-8');
    await fs.rename(tempFile, filePath);
}
async function listPerReminderJsonFiles(dirPath) {
    const entries = await fs.readdir(dirPath, { withFileTypes: true });
    return entries
        .filter((entry) => entry.isFile() && entry.name.endsWith('.json'))
        .map((entry) => entry.name);
}
async function readSharedRemindersUnlocked(target) {
    const dirPath = getSharedReminderDirPath(target);
    let fileNames;
    try {
        fileNames = await listPerReminderJsonFiles(dirPath);
    }
    catch (error) {
        const code = typeof error === 'object' && error !== null ? error.code : undefined;
        if (code === 'ENOENT') {
            return [];
        }
        throw error;
    }
    const reminders = await Promise.all(fileNames.map(async (fileName) => {
        const raw = await fs.readFile(path.join(dirPath, fileName), 'utf-8');
        return materializeStoredReminder(JSON.parse(raw));
    }));
    reminders.sort(tool_1.compareReminderDisplayOrder);
    return reminders;
}
async function writeSharedRemindersUnlocked(target, reminders) {
    const dirPath = getSharedReminderDirPath(target);
    await fs.mkdir(dirPath, { recursive: true });
    const existingFileNames = await listPerReminderJsonFiles(dirPath);
    const desiredIds = new Set();
    for (const reminder of reminders) {
        if (desiredIds.has(reminder.id)) {
            throw new Error(`Duplicate shared reminder_id detected while persisting ${getSharedReminderTargetKey(target)}: ${reminder.id}`);
        }
        desiredIds.add(reminder.id);
    }
    await Promise.all(existingFileNames
        .filter((fileName) => !desiredIds.has(fileName.slice(0, -'.json'.length)))
        .map((fileName) => fs.unlink(path.join(dirPath, fileName))));
    await Promise.all(reminders.map((reminder) => writeReminderSnapshotFile(getSharedReminderFilePath(target, reminder.id), serializeReminder(reminder))));
}
async function loadSharedReminders(target) {
    const lock = getSharedReminderLock(target);
    const release = await lock.acquire();
    try {
        return cloneReminderList(await readSharedRemindersUnlocked(target));
    }
    finally {
        release();
        clearSharedReminderLockIfIdle(target, lock);
    }
}
async function replaceSharedReminders(target, reminders) {
    const lock = getSharedReminderLock(target);
    const release = await lock.acquire();
    try {
        await writeSharedRemindersUnlocked(target, reminders);
    }
    finally {
        release();
        clearSharedReminderLockIfIdle(target, lock);
    }
}
async function mutateSharedReminders(target, mutate) {
    const lock = getSharedReminderLock(target);
    const release = await lock.acquire();
    try {
        const reminders = await readSharedRemindersUnlocked(target);
        const result = await mutate(reminders);
        await writeSharedRemindersUnlocked(target, reminders);
        return result;
    }
    finally {
        release();
        clearSharedReminderLockIfIdle(target, lock);
    }
}
