import { getConfig } from "../../config/index.js";
export function cron(cron, handler) {
    return createScheduledFunction({
        cron,
        handler
    });
}
export function addEventListener(on, handler, options) {
    return createScheduledFunction({
        on,
        handler
    });
}
export function removeEventListener(on, handler, options) {
    const index = SCHEDULED_FUNCTIONS.findIndex(value => (value.on === on &&
        value.handler === handler));
    if (index > -1) {
        SCHEDULED_FUNCTIONS.splice(index, 1);
    }
}
export function on(on, handler, options) {
    return addEventListener(on, handler, options);
}
export function dispatcher(on, handler) {
    return createDispatcherFunction({
        on,
        handler
    });
}
export const SCHEDULED_FUNCTIONS = [];
export const DISPATCHER_FUNCTIONS = new Map();
export function createScheduledFunction(optionsOrFn) {
    const options = parseScheduleOptions(optionsOrFn);
    SCHEDULED_FUNCTIONS.push(options);
    return createRemoveFn(SCHEDULED_FUNCTIONS, options);
}
export function createDispatcherFunction(optionsOrFn) {
    const options = parseScheduleOptions(optionsOrFn);
    const id = getScheduledFunctionCorrelation(options);
    DISPATCHER_FUNCTIONS.set(id, options);
    return () => {
        if (DISPATCHER_FUNCTIONS.get(id) === options) {
            DISPATCHER_FUNCTIONS.delete(id);
        }
    };
}
export function getScheduledFunctionCorrelation(options) {
    if (options.on) {
        return `event:${options.on}`;
    }
    if (options.cron) {
        return `cron:${options.cron}`;
    }
    return "default";
}
export function getScheduledCorrelation(options) {
    if (options.event) {
        if (options.event.durableEventId) {
            return `event:${options.event.type}:${options.event.durableEventId}`;
        }
        return `event:${options.event.type}`;
    }
    if (options.cron) {
        return `cron:${options.cron}`;
    }
    return "default";
}
function createRemoveFn(array, value) {
    return () => {
        const index = array.indexOf(value);
        if (index > -1) {
            array.splice(index, 1);
        }
    };
}
function parseScheduleOptions(optionsOrFn) {
    if (isScheduleFn(optionsOrFn)) {
        return {
            handler: optionsOrFn
        };
    }
    else {
        return optionsOrFn;
    }
    function isScheduleFn(options) {
        return typeof options === "function";
    }
}
export function getScheduledFunctions(options) {
    const config = getConfig();
    return filterScheduledFunctions(config.functions, SCHEDULED_FUNCTIONS, options);
}
export function getDispatcherFunction(options) {
    const config = getConfig();
    const configMatch = getMatchingDispatcher(filterScheduledFunctions(config.dispatchers, [], options), "config");
    if (configMatch) {
        return configMatch;
    }
    return getMatchingDispatcher(filterScheduledFunctions([], [...DISPATCHER_FUNCTIONS.values()], options), "internal");
    function getMatchingDispatcher(dispatchers, name) {
        if (!dispatchers.length) {
            return undefined;
        }
        if (dispatchers.length === 1) {
            return dispatchers[0];
        }
        const match = dispatchers.filter(dispatcher => {
            return ((options.event && dispatcher.on === options.event.type) ||
                (options.cron && dispatcher.cron === options.cron));
        });
        if (match.length === 1) {
            return match[0];
        }
        throw new Error(`Unexpected dispatchers for ${name} state`);
    }
}
function filterScheduledFunctions(config, fns, options) {
    if (options.event) {
        return filterEventScheduled(config, fns, options.event.type);
    }
    let matching = filterDefaultScheduled(config, fns);
    if (options.cron) {
        matching = matching.concat(filterCronScheduled(config, fns, options.cron));
    }
    return matching;
}
function filterEventScheduled(config, fns, event) {
    return filteredScheduledFunctionsWithFn(config, fns, value => value.on === event);
}
function filterCronScheduled(config, fns, cron) {
    return filteredScheduledFunctionsWithFn(config, fns, value => value.cron === cron);
}
function filterDefaultScheduled(config, fns) {
    return filteredScheduledFunctionsWithFn(config, fns, value => !(value.on || value.cron), true);
}
function filteredScheduledFunctionsWithFn(config, fns, filter, isDefault) {
    const internal = fns.filter(filter);
    if (!config)
        return internal;
    if (Array.isArray(config)) {
        return internal.concat(config.filter(filter));
    }
    if (isDefault) {
        return internal;
    }
    const results = internal;
    for (const [on, handler] of Object.entries(config)) {
        const options = {
            on,
            cron: on,
            handler,
        };
        if (filter(options)) {
            results.push(options);
        }
    }
    return results;
}
//# sourceMappingURL=schedule.js.map