import { Logger } from '../config/logger.js';
import { createScheduleRunner } from './index.js';
import { SchedulerLeader } from './leader/SchedulerLeader.js';
const state = {
    runner: createScheduleRunner(),
    registered: new Map(),
    leader: SchedulerLeader.create(),
    leaderStarted: false,
};
const registerMany = (schedules, source = 'core') => {
    for (const schedule of schedules) {
        if (schedule === undefined || schedule === null || typeof schedule.name !== 'string')
            continue;
        const name = schedule.name.trim();
        if (name.length === 0)
            continue;
        const existing = state.registered.get(name);
        // If app already registered, it always wins.
        if (existing === 'app')
            continue;
        // Prevent repeated registrations from the same source.
        if (existing === source)
            continue;
        if (existing === 'core' && source === 'app') {
            Logger.info('Schedule overridden by app/Schedules', { name });
        }
        state.registered.set(name, source);
        state.runner.register(schedule);
    }
};
export const SchedulerRuntime = Object.freeze({
    registerMany,
    start(kernel) {
        // If leader mode is enabled, only the leader instance starts timers.
        if (state.leader.isEnabled()) {
            if (state.leaderStarted)
                return;
            state.leaderStarted = true;
            state.leader.start({
                onBecameLeader: () => {
                    state.runner.start(kernel);
                },
                onLostLeadership: () => {
                    // Best-effort stop; leadership transitions should not crash the process.
                    void state.runner.stop();
                },
            });
            return;
        }
        state.runner.start(kernel);
    },
    async stop(timeoutMs) {
        if (state.leaderStarted) {
            state.leaderStarted = false;
            await state.leader.stop();
        }
        await state.runner.stop(timeoutMs);
    },
    list() {
        return state.runner.list();
    },
    async listWithState() {
        const schedules = state.runner.list();
        const getState = state.runner
            .getState;
        if (typeof getState !== 'function') {
            return schedules.map((schedule) => ({ schedule, state: null }));
        }
        const rows = await Promise.all(schedules.map(async (schedule) => {
            const stateRow = (await getState(schedule.name));
            return { schedule, state: stateRow };
        }));
        return rows;
    },
    async runOnce(name, kernel) {
        await state.runner.runOnce(name, kernel);
    },
});
export default SchedulerRuntime;
