/**
 * Pure evaluators for a single rule condition, shared by the legacy engine
 * (`hourCategorizationService`) and the literal-order executor (`ruleAstExecutor`).
 *
 * Each function isolates one piece of runtime-dependent logic so callers can apply it to
 * whatever interval set they hold (the full worked intervals in legacy, the running result
 * in the literal-order chain):
 * - `resolveThresholdDuration` — the GT/LT threshold as a Duration (resolves `SCHEDULED_HOURS`).
 * - `workedHoursFilterPasses` — the `DAY_TYPE` / `DAY_LIST` gate predicate.
 * - `timeRangeConditionSlot` — the `TIME_RANGE` slot as intervals (caller intersects/differences).
 */

import { WORKDAYS } from '@humand-packages/common';
import { DateTime, Duration, Interval } from 'luxon';
import { TimeTrackingDaySummary } from '../models/daySummary';
import { RuleCondition, TimeSlot } from '../models/hourCategorization';
import { HourCategorizationValidDayTypes } from '../types/hourCategorization/hourCategorizationValidDayTypes';
import { HourCategorizationValueTypes } from '../types/hourCategorization/hourCategorizationValueTypes';
import { DaySummaryScheduleSource } from '../types/scheduleSource';
import { timeSlotToIntervals } from './timeUtils';

/** GT/LT threshold as a Duration. `NUMBER_OF_HOURS` is literal minutes; `SCHEDULED_HOURS` resolves at runtime. */
export function resolveThresholdDuration(condition: RuleCondition, daySummary: TimeTrackingDaySummary): Duration {
    const { valueType, value } = condition;
    if (valueType === HourCategorizationValueTypes.NUMBER_OF_HOURS) {
        return Duration.fromObject({ minutes: Number(value) });
    }
    if (valueType === HourCategorizationValueTypes.SCHEDULED_HOURS) {
        return Duration.fromObject({ hours: daySummary.scheduledHours ?? 0 });
    }
    return Duration.fromMillis(0);
}

/**
 * Whether a `DAY_TYPE` / `DAY_LIST` filter matches the day (all-or-nothing gate).
 * Returns `false` for any unsupported valueType — matching the legacy `default → []`.
 */
export function workedHoursFilterPasses(condition: RuleCondition, daySummary: TimeTrackingDaySummary): boolean {
    const { value, valueType } = condition;

    switch (valueType) {
        case HourCategorizationValueTypes.DAY_TYPE:
            if (value === HourCategorizationValidDayTypes.WORK_DAY) {
                return daySummary.isWorkday && (daySummary.timeOffHours === 0 || daySummary.timeOffHours === null);
            }
            if (value === HourCategorizationValidDayTypes.REST_DAY) {
                return (
                    (daySummary.scheduleSource === DaySummaryScheduleSource.WORK_SCHEDULE &&
                        !daySummary.isWorkday &&
                        (!daySummary.holidays || daySummary.holidays.length === 0)) ||
                    (daySummary.scheduleSource === DaySummaryScheduleSource.SHIFT && !daySummary.isWorkday)
                );
            }
            if (value === HourCategorizationValidDayTypes.HOLIDAY) {
                return !!(daySummary.holidays && daySummary.holidays.length > 0);
            }
            if (value === HourCategorizationValidDayTypes.LEAVE_DAY) {
                return !!(daySummary.isWorkday && daySummary.timeOffHours && daySummary.timeOffHours > 0);
            }
            return false;

        case HourCategorizationValueTypes.DAY_LIST: {
            const dayList = value as WORKDAYS[];
            return dayList.includes(daySummary.weekday as WORKDAYS);
        }

        default:
            return false;
    }
}

/** The `TIME_RANGE` slot resolved to intervals for the day. Empty when the slot is absent. */
export function timeRangeConditionSlot(condition: RuleCondition, daySummary: TimeTrackingDaySummary, timezone: string): Interval[] {
    const timeSlot = condition.value as TimeSlot;
    if (!timeSlot) return [];

    const referenceDate = DateTime.fromISO(daySummary.dateString, { zone: timezone });
    return timeSlotToIntervals(timeSlot, referenceDate, timezone);
}
