import OneUptimeDate from "../Date";
/*
 * CalendarEvent extends JSONObject so it accepts string-indexed metadata.
 * We attach the override info under a known key so downstream consumers can
 * detect and render the substitution distinctly.
 */
export const OVERRIDE_META_KEY = "_override";
export default class UserOverrideUtil {
    /**
     * Decides whether an override should affect resolution for a given policy
     * context. Global overrides (no policy id) always apply. Policy-scoped
     * overrides only apply when their policy matches the caller's policy.
     * When the caller has no policy context, only global overrides apply.
     */
    static isOverrideApplicable(override, currentOnCallDutyPolicyId) {
        if (!override.onCallDutyPolicyId) {
            return true;
        }
        if (!currentOnCallDutyPolicyId) {
            return false;
        }
        return override.onCallDutyPolicyId === currentOnCallDutyPolicyId;
    }
    static applyOverridesToEvents(data) {
        const applicable = data.overrides
            .filter((o) => {
            return UserOverrideUtil.isOverrideApplicable(o, data.currentOnCallDutyPolicyId);
        })
            /*
             * Apply policy-specific overrides before globals so that when both
             * target the same user/window, the policy-specific substitution wins.
             * splitEventByOverride only matches on the original user id, so the
             * first override that consumes a segment claims it.
             */
            .sort((a, b) => {
            const aPolicyScoped = a.onCallDutyPolicyId ? 0 : 1;
            const bPolicyScoped = b.onCallDutyPolicyId ? 0 : 1;
            return aPolicyScoped - bPolicyScoped;
        });
        if (applicable.length === 0) {
            return data.events;
        }
        let working = data.events;
        for (const override of applicable) {
            const next = [];
            for (const event of working) {
                next.push(...UserOverrideUtil.splitEventByOverride(event, override));
            }
            working = next;
        }
        return UserOverrideUtil.reassignEventIds(working);
    }
    static splitEventByOverride(event, override) {
        if (event.title !== override.overrideUserId) {
            return [event];
        }
        // Override window doesn't overlap event window at all.
        if (OneUptimeDate.isAfter(override.startsAt, event.end) ||
            OneUptimeDate.isSame(override.startsAt, event.end) ||
            OneUptimeDate.isBefore(override.endsAt, event.start) ||
            OneUptimeDate.isSame(override.endsAt, event.start)) {
            return [event];
        }
        const overrideStart = OneUptimeDate.isAfter(override.startsAt, event.start)
            ? override.startsAt
            : event.start;
        const overrideEnd = OneUptimeDate.isBefore(override.endsAt, event.end)
            ? override.endsAt
            : event.end;
        const segments = [];
        // Segment before the override window — original user remains on call.
        if (OneUptimeDate.isBefore(event.start, overrideStart)) {
            segments.push(Object.assign(Object.assign({}, event), { end: overrideStart }));
        }
        // Override window — substitute user takes over.
        const meta = {
            isOverride: true,
            originalUserId: override.overrideUserId,
            overrideUserId: override.routeAlertsToUserId,
            overrideStartsAt: override.startsAt,
            overrideEndsAt: override.endsAt,
        };
        segments.push(Object.assign(Object.assign({}, event), { start: overrideStart, end: overrideEnd, title: override.routeAlertsToUserId, [OVERRIDE_META_KEY]: meta }));
        // Segment after the override window — original user resumes.
        if (OneUptimeDate.isAfter(event.end, overrideEnd)) {
            segments.push(Object.assign(Object.assign({}, event), { start: overrideEnd }));
        }
        return segments;
    }
    static reassignEventIds(events) {
        let id = 1;
        return events.map((event) => {
            return Object.assign(Object.assign({}, event), { id: id++ });
        });
    }
    static getOverrideMeta(event) {
        const meta = event[OVERRIDE_META_KEY];
        if (meta &&
            typeof meta === "object" &&
            meta.isOverride === true) {
            return meta;
        }
        return null;
    }
}
//# sourceMappingURL=UserOverrideUtil.js.map