"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getOrRestoreMainDialog = getOrRestoreMainDialog;
exports.ensureDialogLoaded = ensureDialogLoaded;
const diligence_1 = require("@longrun-ai/kernel/diligence");
const dialog_1 = require("./dialog");
const dialog_global_registry_1 = require("./dialog-global-registry");
const persistence_1 = require("./persistence");
const team_1 = require("./team");
function resolveMemberDiligencePushMax(team, agentId) {
    const member = team.getMember(agentId);
    if (member && member.diligence_push_max !== undefined) {
        return member.diligence_push_max;
    }
    return diligence_1.DEFAULT_DILIGENCE_PUSH_MAX;
}
function normalizeDiligencePushMax(value) {
    if (!Number.isFinite(value))
        return 0;
    return Math.floor(value);
}
function clampNonNegativeFiniteInt(value, fallback) {
    if (typeof value !== 'number' || !Number.isFinite(value))
        return fallback;
    return Math.max(0, Math.floor(value));
}
async function resolvePendingRuntimePromptForRestore(args) {
    const pending = args.latest?.pendingRuntimePrompt;
    if (!pending) {
        return { pendingRuntimePrompt: undefined };
    }
    const alreadyPersisted = args.messages.some((message) => {
        return message.type === 'prompting_msg' && message.msgId === pending.msgId;
    });
    if (alreadyPersisted) {
        if (args.status === 'running') {
            await persistence_1.DialogPersistence.clearPendingRuntimePrompt(args.dialogId, pending.msgId, args.status);
            const latestAfterClear = await persistence_1.DialogPersistence.loadDialogLatest(args.dialogId, args.status);
            if (latestAfterClear) {
                await persistence_1.DialogPersistence.syncWakeQueueForDialogLatest(args.dialogId, latestAfterClear, args.status);
            }
            else {
                await persistence_1.DialogPersistence.removeWakeQueueEntriesForDialog(args.dialogId, args.status);
            }
        }
        return { pendingRuntimePrompt: undefined };
    }
    return { pendingRuntimePrompt: pending };
}
async function getOrRestoreMainDialog(rootId, status) {
    const existing = dialog_global_registry_1.globalDialogRegistry.get(rootId);
    if (existing) {
        existing.setPersistenceStatus(status);
        await existing.loadSideDialogRegistry();
        await existing.loadActiveCalleeDispatchesFromPersistence();
        return existing;
    }
    const mainDialogId = new dialog_1.DialogID(rootId);
    const rootState = await persistence_1.DialogPersistence.restoreDialog(mainDialogId, status);
    if (!rootState)
        return undefined;
    const rootMetadata = rootState.metadata;
    const latest = await persistence_1.DialogPersistence.loadDialogLatest(mainDialogId, status);
    const { pendingRuntimePrompt } = await resolvePendingRuntimePromptForRestore({
        dialogId: mainDialogId,
        status,
        messages: rootState.messages,
        latest,
    });
    let diligencePushMax = diligence_1.DEFAULT_DILIGENCE_PUSH_MAX;
    try {
        const team = await team_1.Team.load();
        diligencePushMax = normalizeDiligencePushMax(resolveMemberDiligencePushMax(team, rootMetadata.agentId));
    }
    catch (_err) {
        diligencePushMax = diligence_1.DEFAULT_DILIGENCE_PUSH_MAX;
    }
    const defaultDisableDiligencePush = false;
    const rootStore = new persistence_1.DiskFileDialogStore(mainDialogId);
    const mainDialog = new dialog_1.MainDialog(rootStore, rootMetadata.taskDocPath, mainDialogId, rootMetadata.agentId, {
        messages: rootState.messages,
        reminders: rootState.reminders,
        currentCourse: rootState.currentCourse,
        contextHealth: rootState.contextHealth,
        pendingRuntimePrompt,
    });
    const persistedDisableDiligencePush = latest && typeof latest.disableDiligencePush === 'boolean'
        ? latest.disableDiligencePush
        : defaultDisableDiligencePush;
    mainDialog.disableDiligencePush = persistedDisableDiligencePush;
    const persistedRemainingBudget = latest && typeof latest.diligencePushRemainingBudget === 'number'
        ? latest.diligencePushRemainingBudget
        : undefined;
    const normalizedRemainingBudget = clampNonNegativeFiniteInt(persistedRemainingBudget, diligencePushMax > 0 ? diligencePushMax : 0);
    // `diligence-push-max` only seeds defaults. Persisted per-dialog budget is the runtime source of
    // truth, including operator-added budget above (or despite) the current team default.
    mainDialog.diligencePushRemainingBudget = normalizedRemainingBudget;
    mainDialog.setPersistenceStatus(status);
    dialog_global_registry_1.globalDialogRegistry.register(mainDialog);
    // Keep the in-memory main dialog fully hydrated regardless of persistence status
    // (running/completed/archived) so sideDialog lookup is stable across UI navigation.
    await mainDialog.loadSideDialogRegistry();
    await mainDialog.loadActiveCalleeDispatchesFromPersistence();
    return mainDialog;
}
async function ensureDialogLoaded(mainDialog, targetId, status, visitedSelfIds = new Set()) {
    if (targetId.selfId === targetId.rootId)
        return mainDialog;
    const existing = mainDialog.lookupDialog(targetId.selfId);
    if (existing)
        return existing;
    if (visitedSelfIds.has(targetId.selfId))
        return undefined;
    visitedSelfIds.add(targetId.selfId);
    const metadata = await persistence_1.DialogPersistence.loadDialogMetadata(targetId, status);
    if (!metadata)
        return undefined;
    const askerStack = await persistence_1.DialogPersistence.loadSideDialogAskerStackState(targetId, status);
    if (!askerStack) {
        throw new Error(`ensureDialogLoaded invariant violation: missing asker stack for ${targetId.valueOf()}`);
    }
    const askerStackTop = askerStack.askerStack[askerStack.askerStack.length - 1];
    if (!askerStackTop) {
        throw new Error(`ensureDialogLoaded invariant violation: empty askerDialog stack for ${targetId.valueOf()}`);
    }
    // Ensure asker dialog exists in root registry for dynamic asker/askerDialog resolution.
    if (askerStackTop.askerDialogId !== targetId.rootId) {
        await ensureDialogLoaded(mainDialog, new dialog_1.DialogID(askerStackTop.askerDialogId, targetId.rootId), status, visitedSelfIds);
    }
    const state = await persistence_1.DialogPersistence.restoreDialog(targetId, status);
    if (!state)
        return undefined;
    const latest = await persistence_1.DialogPersistence.loadDialogLatest(targetId, status);
    const { pendingRuntimePrompt } = await resolvePendingRuntimePromptForRestore({
        dialogId: targetId,
        status,
        messages: state.messages,
        latest,
    });
    const assignmentFromAsker = (() => {
        for (let index = askerStack.askerStack.length - 1; index >= 0; index -= 1) {
            const frame = askerStack.askerStack[index];
            if (frame?.assignmentFromAsker !== undefined) {
                return frame.assignmentFromAsker;
            }
        }
        throw new Error(`ensureDialogLoaded invariant violation: missing assignment frame in asker stack for ${targetId.valueOf()}`);
    })();
    // Ensure the tellasker exists so SideDialog can resolve its effective askerDialog.
    if (assignmentFromAsker.askerDialogId &&
        assignmentFromAsker.askerDialogId !== targetId.rootId &&
        assignmentFromAsker.askerDialogId !== targetId.selfId) {
        await ensureDialogLoaded(mainDialog, new dialog_1.DialogID(assignmentFromAsker.askerDialogId, targetId.rootId), status, visitedSelfIds);
    }
    const store = new persistence_1.DiskFileDialogStore(targetId);
    const sideDialog = new dialog_1.SideDialog(store, mainDialog, metadata.taskDocPath, targetId, metadata.agentId, askerStack, metadata.sessionSlug, {
        messages: state.messages,
        reminders: state.reminders,
        currentCourse: state.currentCourse,
        contextHealth: state.contextHealth,
        pendingRuntimePrompt,
    });
    sideDialog.disableDiligencePush =
        latest && typeof latest.disableDiligencePush === 'boolean'
            ? latest.disableDiligencePush
            : false;
    if (sideDialog.sessionSlug) {
        mainDialog.registerSideDialog(sideDialog);
    }
    return sideDialog;
}
