import { getSession, getClaudeSessionIdsByConversationElementId } from "../lib/neo4j.js";
import { emptyTrash } from "../../../../../lib/graph-trash/dist/index.js";
import { purgeAdminConversationJsonls } from "../../../../../lib/admin-conversation-purge/dist/index.js";
import { removeAttachmentDir } from "../lib/attachments.js";
import { withWriteEvent } from "../lib/log-ingest.js";
import { checkLabelDeleteGate } from "../lib/label-delete-gate.js";
export async function memoryEmptyTrash(params) {
    return withWriteEvent({ tool: "memory-empty-trash", accountId: params.accountId, labels: params.labels }, () => memoryEmptyTrashImpl(params));
}
function resolveManagerBase(explicit) {
    if (explicit)
        return explicit;
    const port = process.env.CLAUDE_SESSION_MANAGER_PORT;
    if (!port)
        return null;
    const parsed = Number(port);
    if (!Number.isFinite(parsed) || parsed <= 0 || parsed >= 65536)
        return null;
    return `http://127.0.0.1:${parsed}`;
}
async function memoryEmptyTrashImpl(params) {
    const { accountId, graceDays, dryRun, labels, fetchImpl, origin } = params;
    const managerBase = resolveManagerBase(params.managerBase);
    const session = getSession();
    let attachmentDirsRemoved = 0;
    let adminConversationsPurged = 0;
    try {
        const result = await emptyTrash({
            session,
            accountId,
            graceDays,
            dryRun,
            labels,
            onEmpty: async (c) => {
                // Task 443 — refuse hard-delete of trashed `:LocalBusiness`
                // candidates unless the sweep was started with `origin: "system"`.
                // Throwing here makes `emptyTrash` skip the `DETACH DELETE` for
                // this candidate and continue draining the rest of the batch.
                const deleteGate = checkLabelDeleteGate({
                    labels: c.labels,
                    origin,
                    accountId,
                    elementId: c.elementId,
                    tool: "memory-empty-trash",
                });
                if (!deleteGate.ok) {
                    process.stderr.write(`[trash:empty-skip-reserved] accountId=${accountId} elementId=${c.elementId} label=LocalBusiness\n`);
                    throw new Error(deleteGate.message);
                }
                if (c.labels.includes("AdminConversation")) {
                    await purgeAdminConversationForCandidate(c, accountId, managerBase, fetchImpl);
                    adminConversationsPurged++;
                    return;
                }
                if (c.labels.includes("KnowledgeDocument")) {
                    const aid = typeof c.trashedKeys.attachmentId === "string"
                        ? c.trashedKeys.attachmentId
                        : null;
                    if (!aid)
                        return;
                    const removed = await removeAttachmentDir(accountId, aid);
                    if (removed) {
                        attachmentDirsRemoved++;
                        process.stderr.write(`[trash:emptied:disk] accountId=${accountId} attachmentId=${aid}\n`);
                    }
                }
            },
        });
        return { ...result, attachmentDirsRemoved, adminConversationsPurged };
    }
    finally {
        await session.close();
    }
}
async function purgeAdminConversationForCandidate(candidate, accountId, managerBase, fetchImpl) {
    const rawSessionId = candidate.trashedKeys.sessionId;
    const sessionId = typeof rawSessionId === "string" && rawSessionId.length > 0
        ? rawSessionId
        : null;
    if (!sessionId) {
        throw new Error(`AdminConversation elementId=${candidate.elementId.slice(0, 8)} has no sessionId in _trashedKeys — refusing to DETACH DELETE without JSONL purge attempt`);
    }
    if (!managerBase) {
        process.stderr.write(`[trash:empty-run] reason=jsonl-purge-failed sessionId=${sessionId.slice(0, 8)} message=manager-port-missing\n`);
        throw new Error(`manager-port-missing — set CLAUDE_SESSION_MANAGER_PORT to purge :AdminConversation JSONLs`);
    }
    const claudeSessionIds = await getClaudeSessionIdsByConversationElementId(candidate.elementId, accountId);
    const outcome = await purgeAdminConversationJsonls({
        sessionId,
        accountId,
        managerBase,
        claudeSessionIds,
        fetchImpl,
    });
    if (!outcome.ok) {
        const claudeSessionId = outcome.claudeSessionId.slice(0, 8);
        const message = outcome.reason === "pty-still-alive"
            ? "pty-still-alive"
            : `${outcome.reason}:${outcome.message}`;
        process.stderr.write(`[trash:empty-run] reason=jsonl-purge-failed sessionId=${sessionId.slice(0, 8)} claudeSessionId=${claudeSessionId} message=${message}\n`);
        throw new Error(`jsonl-purge-failed for claudeSessionId=${claudeSessionId}: ${message}`);
    }
}
//# sourceMappingURL=memory-empty-trash.js.map