"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScheduleState = exports.Interval = exports.ScheduleConfig = void 0;
class ScheduleConfig {
    frequency;
    interval;
    time;
    dayOfMonth;
    // 7 bools, one for each day of week. Starting on Sunday.
    daysOfWeek;
    // Added in order to compute locale timezone differences after/before DST
    // It will be missing for the old scheduled jobs and default to UTC
    timezoneLocale;
    constructor({ frequency, interval, time, dayOfMonth, daysOfWeek, timezoneLocale: timezoneLocale }) {
        this.frequency = frequency;
        this.interval = interval;
        this.time = time;
        this.dayOfMonth = dayOfMonth;
        this.daysOfWeek = daysOfWeek;
        this.timezoneLocale = timezoneLocale || 'UTC';
    }
    static validate(config) {
        const validIntervals = [Interval.Minute, Interval.Hour, Interval.Day, Interval.Week, Interval.Month];
        if (!Number.isInteger(config.frequency)) {
            return { error: 'Frequency should be an integer.' };
        }
        if (config.frequency < 0) {
            return { error: 'Frequency should be greater than 0.' };
        }
        if (!validIntervals.includes(config.interval)) {
            return { error: `Invalid interval ${config.interval}.` };
        }
        if (config.daysOfWeek.length !== 7) {
            return { error: `Invalid interval config daysOfWeek. ${config.daysOfWeek}` };
        }
        if (!config.dayOfMonth || !Number.isInteger(config.dayOfMonth)) {
            return { error: `Invalid dayOfMonth. ${config.dayOfMonth}` };
        }
        // TODO validate locale
        return { error: undefined };
    }
    static default() {
        return new ScheduleConfig({
            frequency: 1,
            interval: Interval.Month,
            time: midnight(),
            dayOfMonth: 1,
            daysOfWeek: [true, false, false, false, false, false, false],
            // In Server, this would resolve to UTC, in UI to the local timezone
            timezoneLocale: Intl.DateTimeFormat().resolvedOptions().timeZone
        });
    }
    cronDaysOfWeek() {
        const selectedDays = this.daysOfWeek.flatMap((bool, index) => (bool ? index : []));
        return selectedDays.length === 0 ? '*' : selectedDays.join(',');
    }
    getLocalMinutesAndHoursAndDays() {
        // For historical reasons, we are saving the time in UTC. This is causing problem when we have DST changes
        // Ideally, instead of storing a datetime object, we should store hours and minutes in the local timezone
        // so that we can pass timezone to cron parser and it will take care of DST changes. This is basically
        // equavelant to storing a cron spec. Which we should do in the future.
        // For the time being, we are converting the time to the local timezone and then computing the minutes and hours
        // Here is how it works:
        //   * Get the local hours/minutes from the day the job was first created
        //      -> /E.g. UTC 23:00 is 19:00 in New York during DST, 18:00 otherwise
        //   * Add these local hours/minutes to cron expression
        //   * Tell cron expression that we want next run in a specific timezone
        //   * Cron expression decipher timezone and gives us a date which we store as UTC in Schedule table.
        const localTime = new Date(this.time.toLocaleString('en', { timeZone: this.timezoneLocale }));
        return [localTime.getMinutes(), localTime.getHours()];
    }
    // Currently, we use a cron evaluator to evaluate recurrence
    // expressions.
    toCron() {
        const [localMinutes, localHours] = this.getLocalMinutesAndHoursAndDays();
        switch (this.interval) {
            case Interval.Minute:
                // e.g. '*/2 * * *' -> every 2 minutes of the hour
                return `*/${this.frequency} * * * *`;
            case Interval.Hour:
                // 'mm */2 * * *' -> every 2 hours every day at mm
                return `${localMinutes} */${this.frequency} * * *`;
            case Interval.Day:
                // 'mm hh * * *' -> every day at hh:mm
                return `${localMinutes} ${localHours} * * *`;
            case Interval.Week:
                // 'mm hh * * 0,2' -> every week at hh:mm on Sunday and Tuesday
                return `${localMinutes} ${localHours} * * ${this.cronDaysOfWeek()}`;
            case Interval.Month:
                // 'mm hh dom */2 *' -> every 2 months on dom at hh:ss
                return `${localMinutes} ${localHours} ${this.dayOfMonth} */${this.frequency} *`;
        }
    }
}
exports.ScheduleConfig = ScheduleConfig;
var Interval;
(function (Interval) {
    Interval["Minute"] = "minute";
    Interval["Hour"] = "hour";
    Interval["Day"] = "day";
    Interval["Week"] = "week";
    Interval["Month"] = "month";
})(Interval || (exports.Interval = Interval = {}));
const midnight = () => {
    const d = new Date();
    d.setHours(0);
    d.setMinutes(0);
    d.setSeconds(0);
    d.setMilliseconds(0);
    return d;
};
var ScheduleState;
(function (ScheduleState) {
    ScheduleState[ScheduleState["ACTIVE"] = 0] = "ACTIVE";
    ScheduleState[ScheduleState["PAUSED"] = 1] = "PAUSED";
})(ScheduleState || (exports.ScheduleState = ScheduleState = {}));
//# sourceMappingURL=schedule.js.map