/**
 * Safely stringifies interruption arguments for storage and display.
 */
export const serializeInterruptionPayload = (value) => {
    if (value === undefined || value === null) {
        return '';
    }
    if (typeof value === 'string') {
        return value;
    }
    try {
        return JSON.stringify(value);
    }
    catch (error) {
        console.warn('Failed to stringify interruption payload', error);
        return String(value);
    }
};
/**
 * Drops internal handles from an interruption while preserving user-facing fields.
 */
export const toPublicInterruption = (entry) => ({
    id: entry.id,
    runId: entry.runId,
    callId: entry.callId,
    toolName: entry.toolName,
    toolArguments: entry.toolArguments,
    agentName: entry.agentName,
    message: entry.message,
    createdAt: entry.createdAt,
    updatedAt: entry.updatedAt,
    resolvedAt: entry.resolvedAt,
    status: entry.status,
    rawItem: entry.rawItem
});
/**
 * Normalizes a raw tool approval interruption into our tracked shape.
 */
export const buildToolApprovalInterruption = (runId, interruption, timestamp, index) => {
    const interruptionJson = interruption.toJSON?.() ?? {};
    const rawItem = (interruptionJson.rawItem ?? interruption.rawItem ?? {});
    const statusRaw = typeof rawItem.status === 'string' ? rawItem.status.toLowerCase() : undefined;
    const approvedStatuses = new Set([
        'approved',
        'granted',
        'allow',
        'allowed',
        'complete',
        'done',
        'success',
        'succeeded',
        'resolved'
    ]);
    const rejectedStatuses = new Set([
        'rejected',
        'denied',
        'declined',
        'cancelled',
        'canceled',
        'failed',
        'failure',
        'error'
    ]);
    let status = 'pending';
    if (statusRaw && approvedStatuses.has(statusRaw)) {
        status = 'approved';
    }
    else if (statusRaw && rejectedStatuses.has(statusRaw)) {
        status = 'rejected';
    }
    else if (statusRaw === 'completed') {
        status = 'pending';
    }
    const callIdCandidates = [rawItem.callId, rawItem.id, rawItem.name];
    const callId = callIdCandidates.find((value) => typeof value === 'string' && value.length > 0)
        ?? `tool-call-${runId}-${index}`;
    const interruptionId = typeof rawItem.id === 'string' && rawItem.id.length > 0
        ? rawItem.id
        : `${runId}-${callId}`;
    const toolArguments = serializeInterruptionPayload(rawItem.arguments ?? rawItem.input);
    const agentName = typeof interruptionJson.agent?.name === 'string'
        ? interruptionJson.agent.name
        : interruption.agent?.name;
    return {
        id: interruptionId,
        runId,
        callId,
        toolName: typeof rawItem.name === 'string' ? rawItem.name : undefined,
        toolArguments,
        agentName,
        message: typeof rawItem.message === 'string' ? rawItem.message : undefined,
        createdAt: timestamp,
        updatedAt: timestamp,
        status,
        rawItem,
        source: interruption,
        rawInterruption: interruption,
        resolvedAt: status === 'pending' ? undefined : timestamp
    };
};
const extractInterruptionMetadata = (interruption) => {
    const interruptionJson = interruption.toJSON?.() ?? {};
    const rawItem = (interruptionJson.rawItem ?? interruption.rawItem ?? {});
    const callId = typeof rawItem.callId === 'string' ? rawItem.callId : undefined;
    const id = typeof rawItem.id === 'string' ? rawItem.id : undefined;
    const name = typeof rawItem.name === 'string' ? rawItem.name : undefined;
    return { callId, id, name, rawItem };
};
const matchInterruption = (details, pool) => {
    if (pool.length === 0) {
        return undefined;
    }
    const findByPredicate = (predicate) => {
        const index = pool.findIndex((candidate) => predicate(extractInterruptionMetadata(candidate)));
        if (index >= 0) {
            const [match] = pool.splice(index, 1);
            return match;
        }
        return undefined;
    };
    if (details.callId) {
        const match = findByPredicate((metadata) => metadata.callId === details.callId || metadata.id === details.callId);
        if (match) {
            return match;
        }
    }
    if (details.id) {
        const match = findByPredicate((metadata) => metadata.id === details.id);
        if (match) {
            return match;
        }
    }
    if (details.toolName) {
        const match = findByPredicate((metadata) => metadata.name === details.toolName);
        if (match) {
            return match;
        }
    }
    if (details.status === 'pending') {
        return pool.shift();
    }
    return undefined;
};
/**
 * Re-links serialized interruptions with live run handles where possible.
 */
export const hydrateInternalInterruptions = (runId, details, rawInterruptions) => {
    const pool = [...rawInterruptions];
    return details.map((detail) => {
        const match = matchInterruption(detail, pool);
        const metadata = match ? extractInterruptionMetadata(match) : { rawItem: detail.rawItem };
        return {
            ...detail,
            runId,
            rawItem: detail.rawItem ?? metadata.rawItem,
            source: match,
            rawInterruption: match
        };
    });
};
