import { logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
import { computeNextRun } from './manager-runtime-helpers.js';
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils/error-display';
const MAX_TIMEOUT_MS = 24 * 60 * 60 * 1000;
export function scheduleAutomationJob(context, job) {
    cancelAutomationTimer(context.timers, job.id);
    if (!context.running() || !job.enabled)
        return;
    const catchUpWindowMs = Number(context.configManager.get('automation.catchUpWindowMinutes') ?? 30) * 60_000;
    const nextRunAtCandidate = job.nextRunAt ?? computeNextRun(job.schedule, Date.now(), job.id);
    const nextRunAt = nextRunAtCandidate !== undefined && nextRunAtCandidate < (Date.now() - catchUpWindowMs)
        ? computeNextRun(job.schedule, Date.now(), job.id)
        : nextRunAtCandidate;
    if (nextRunAt === undefined)
        return;
    const refreshed = {
        ...job,
        nextRunAt,
    };
    context.jobs.set(job.id, refreshed);
    void context.saveJobs();
    const delayMs = Math.max(0, nextRunAt - Date.now());
    if (delayMs > MAX_TIMEOUT_MS) {
        const timer = setTimeout(() => scheduleAutomationJob(context, refreshed), MAX_TIMEOUT_MS);
        context.timers.set(job.id, timer);
        return;
    }
    const timer = setTimeout(() => {
        const latest = context.jobs.get(job.id);
        if (!latest?.enabled)
            return;
        if (latest.execution.wakeMode === 'next-heartbeat') {
            queueHeartbeatWake(context.heartbeatWakes, latest, 'scheduled', true, 1, 'scheduled-due');
            return;
        }
        if (context.activeRunCount() >= context.maxConcurrentRuns()) {
            const deferred = {
                ...latest,
                nextRunAt: Date.now() + 15_000,
                updatedAt: Date.now(),
            };
            context.jobs.set(latest.id, deferred);
            void context.saveJobs();
            scheduleAutomationJob(context, deferred);
            return;
        }
        void context.executeJob(latest, 'scheduled', true)
            .catch((error) => {
            logger.error('AutomationManager: scheduled execution failed', {
                jobId: latest.id,
                error: summarizeError(error),
            });
        })
            .finally(() => {
            const current = context.jobs.get(job.id);
            if (!current?.enabled)
                return;
            const next = computeNextRun(current.schedule, Date.now(), current.id);
            if (next !== undefined) {
                const updated = {
                    ...current,
                    nextRunAt: next,
                    updatedAt: Date.now(),
                };
                context.jobs.set(current.id, updated);
                void context.saveJobs();
                scheduleAutomationJob(context, updated);
                return;
            }
            const completedOneShot = {
                ...current,
                enabled: false,
                status: 'paused',
                pausedReason: 'one-shot-complete',
                nextRunAt: undefined,
                updatedAt: Date.now(),
            };
            context.jobs.set(current.id, completedOneShot);
            cancelAutomationTimer(context.timers, current.id);
            void context.saveJobs();
        });
    }, delayMs);
    context.timers.set(job.id, timer);
}
export function cancelAutomationTimer(timers, jobId) {
    const timer = timers.get(jobId);
    if (timer) {
        clearTimeout(timer);
        timers.delete(jobId);
    }
}
export function queueDueHeartbeatAutomationJobs(jobs, heartbeatWakes, reason) {
    const now = Date.now();
    for (const job of jobs) {
        if (!job.enabled || job.execution.wakeMode !== 'next-heartbeat')
            continue;
        if (job.nextRunAt === undefined || job.nextRunAt > now)
            continue;
        queueHeartbeatWake(heartbeatWakes, job, 'scheduled', true, 1, reason);
    }
}
export function queueHeartbeatWake(heartbeatWakes, job, trigger, dueRun, attempt, reason) {
    if (heartbeatWakes.has(job.id))
        return;
    heartbeatWakes.set(job.id, {
        jobId: job.id,
        jobName: job.name,
        trigger,
        dueRun,
        attempt,
        queuedAt: Date.now(),
        reason,
    });
}
export function advanceScheduledHeartbeatAutomationJob(context, timers, jobId, reschedule) {
    const current = context.jobs.get(jobId);
    if (!current?.enabled)
        return;
    const next = computeNextRun(current.schedule, Date.now(), current.id);
    if (next !== undefined) {
        const updated = {
            ...current,
            nextRunAt: next,
            updatedAt: Date.now(),
        };
        context.jobs.set(current.id, updated);
        void context.saveJobs();
        reschedule(updated);
        return;
    }
    const completedOneShot = {
        ...current,
        enabled: false,
        status: 'paused',
        pausedReason: 'one-shot-complete',
        nextRunAt: undefined,
        updatedAt: Date.now(),
    };
    context.jobs.set(current.id, completedOneShot);
    cancelAutomationTimer(timers, current.id);
    void context.saveJobs();
}
