let clockOffsetMs = 0;
const CLOCK_OVERDUE_AUTO_REMOVE_MS = 60_000;
function normalizeRecurrence(raw) {
    if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
        return undefined;
    }
    const record = raw;
    const rawKind = typeof record.kind === 'string' ? record.kind.trim().toLowerCase() : '';
    const kind = rawKind === 'daily' || rawKind === 'weekly' || rawKind === 'interval'
        ? rawKind
        : undefined;
    const maxRunsRaw = Number(record.maxRuns);
    const maxRuns = Number.isFinite(maxRunsRaw) ? Math.floor(maxRunsRaw) : NaN;
    if (!kind || !Number.isFinite(maxRuns) || maxRuns <= 0) {
        return undefined;
    }
    if (kind === 'interval') {
        const minutesRaw = Number(record.everyMinutes);
        const everyMinutes = Number.isFinite(minutesRaw) ? Math.floor(minutesRaw) : NaN;
        if (!Number.isFinite(everyMinutes) || everyMinutes <= 0) {
            return undefined;
        }
        return { kind, maxRuns, everyMinutes };
    }
    return { kind, maxRuns };
}
function normalizeTaskSetter(raw) {
    const value = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
    if (value === 'agent') {
        return 'agent';
    }
    return 'user';
}
export function setClockOffsetMs(value) {
    if (typeof value !== 'number' || !Number.isFinite(value))
        return;
    clockOffsetMs = Math.max(-24 * 60 * 60_000, Math.min(24 * 60 * 60_000, Math.floor(value)));
}
export function getClockOffsetMs() {
    return clockOffsetMs;
}
export function nowMs() {
    return Date.now() + clockOffsetMs;
}
export function buildEmptyState(sessionId) {
    const t = nowMs();
    return { version: 1, sessionId, tasks: [], updatedAtMs: t };
}
export function coerceState(raw, sessionId) {
    if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
        return buildEmptyState(sessionId);
    }
    const record = raw;
    const tasksRaw = Array.isArray(record.tasks) ? record.tasks : [];
    const tasks = [];
    for (const entry of tasksRaw) {
        if (!entry || typeof entry !== 'object' || Array.isArray(entry))
            continue;
        const e = entry;
        const taskId = typeof e.taskId === 'string' ? e.taskId.trim() : '';
        const dueAtMs = typeof e.dueAtMs === 'number' && Number.isFinite(e.dueAtMs) ? Math.floor(e.dueAtMs) : NaN;
        const createdAtMs = typeof e.createdAtMs === 'number' && Number.isFinite(e.createdAtMs) ? Math.floor(e.createdAtMs) : NaN;
        const updatedAtMs = typeof e.updatedAtMs === 'number' && Number.isFinite(e.updatedAtMs) ? Math.floor(e.updatedAtMs) : NaN;
        const task = typeof e.task === 'string' ? e.task.trim() : '';
        if (!taskId || !task || !Number.isFinite(dueAtMs) || !Number.isFinite(createdAtMs) || !Number.isFinite(updatedAtMs)) {
            continue;
        }
        const tool = typeof e.tool === 'string' && e.tool.trim() ? e.tool.trim() : undefined;
        const args = e.arguments && typeof e.arguments === 'object' && !Array.isArray(e.arguments)
            ? e.arguments
            : undefined;
        const deliveredAtMs = typeof e.deliveredAtMs === 'number' && Number.isFinite(e.deliveredAtMs) ? Math.floor(e.deliveredAtMs) : undefined;
        const notBeforeRequestId = typeof e.notBeforeRequestId === 'string' && e.notBeforeRequestId.trim().length
            ? e.notBeforeRequestId.trim()
            : undefined;
        const deliveryCount = typeof e.deliveryCount === 'number' && Number.isFinite(e.deliveryCount) ? Math.max(0, Math.floor(e.deliveryCount)) : 0;
        const recurrence = normalizeRecurrence(e.recurrence);
        const setBy = normalizeTaskSetter(e.setBy);
        tasks.push({
            taskId,
            sessionId,
            dueAtMs,
            createdAtMs,
            updatedAtMs,
            setBy,
            task,
            ...(tool ? { tool } : {}),
            ...(args ? { arguments: args } : {}),
            ...(deliveredAtMs !== undefined ? { deliveredAtMs } : {}),
            deliveryCount,
            ...(notBeforeRequestId ? { notBeforeRequestId } : {}),
            ...(recurrence ? { recurrence } : {})
        });
    }
    const updatedAtMs = typeof record.updatedAtMs === 'number' && Number.isFinite(record.updatedAtMs) ? Math.floor(record.updatedAtMs) : nowMs();
    return { version: 1, sessionId, tasks, updatedAtMs };
}
export function cleanExpiredTasks(tasks, config, atMs) {
    const out = [];
    for (const task of tasks) {
        if (!task || typeof task !== 'object')
            continue;
        if (!Number.isFinite(task.dueAtMs))
            continue;
        const recurrence = normalizeRecurrence(task.recurrence);
        const deliveryCount = typeof task.deliveryCount === 'number' && Number.isFinite(task.deliveryCount)
            ? Math.max(0, Math.floor(task.deliveryCount))
            : 0;
        if (recurrence) {
            if (deliveryCount >= recurrence.maxRuns) {
                continue;
            }
            out.push({ ...task, recurrence });
            continue;
        }
        const oneShotRetentionMs = Math.max(0, Math.min(config.retentionMs, CLOCK_OVERDUE_AUTO_REMOVE_MS));
        if (atMs > task.dueAtMs + oneShotRetentionMs) {
            continue;
        }
        out.push(task);
    }
    return out;
}
