/**
 * Phase 1 — pure construction of a rule's linear-chain AST from its conditions, in **literal
 * array order**. No `daySummary`/`timezone`: only the rule's static structure is read here.
 * Runtime values (`SCHEDULED_HOURS`, slot intervals, day gates) are resolved by `executeRuleAst`.
 *
 * Classification matches the legacy engine (`isThresholdCondition`): a threshold is
 * `field=WORKED_HOURS` with valueType `NUMBER_OF_HOURS` | `SCHEDULED_HOURS`, GT/LT by operator;
 * everything else is a filter.
 */

import { HourCategorizationRule, RuleCondition } from '../models/hourCategorization';
import { RuleAstNode, StageNode } from '../models/timeTracking/ruleAst';
import { HourCategorizationFields } from '../types/hourCategorization/hourCategorizationFields';
import { HourCategorizationOperators } from '../types/hourCategorization/hourCategorizationOperators';
import { HourCategorizationValueTypes } from '../types/hourCategorization/hourCategorizationValueTypes';

function isThresholdCondition(condition: RuleCondition): boolean {
    return (
        condition.field === HourCategorizationFields.WORKED_HOURS &&
        (condition.valueType === HourCategorizationValueTypes.NUMBER_OF_HOURS || condition.valueType === HourCategorizationValueTypes.SCHEDULED_HOURS)
    );
}

/** Builds the stage node for one condition, chained onto `input`. Returns `null` for a no-op condition. */
function buildStage(condition: RuleCondition, input: StageNode): StageNode | null {
    if (isThresholdCondition(condition)) {
        if (condition.operator === HourCategorizationOperators.GREATER_THAN) {
            return { kind: 'THRESHOLD_GT', condition, thresholdMs: 0, input, resultIntervals: [], resultHours: 0 };
        }
        if (condition.operator === HourCategorizationOperators.LESS_THAN) {
            return { kind: 'THRESHOLD_LT', condition, thresholdMs: 0, input, resultIntervals: [], resultHours: 0 };
        }
        // An EQUALS / NOT_EQUALS threshold is classified as a threshold but matches no GT/LT branch
        // in the legacy engine → silently ignored. Preserve that: contribute no stage.
        return null;
    }

    if (condition.field === HourCategorizationFields.TIME_RANGE) {
        // Legacy `calculateTimeRangeConditionIntervals` returns [] for a TIME_RANGE-field condition
        // whose valueType is not TIME_RANGE (the VC validates field and valueType independently, so
        // this combination is reachable). Preserve that — don't feed a non-slot value to the slot resolver.
        if (condition.valueType !== HourCategorizationValueTypes.TIME_RANGE) {
            return { kind: 'FILTER', op: 'EMPTY', condition, input, resultIntervals: [], resultHours: 0 };
        }
        const op = condition.operator === HourCategorizationOperators.EQUALS ? 'INTERSECT' : 'DIFFERENCE';
        return { kind: 'FILTER', op, condition, input, resultIntervals: [], resultHours: 0 };
    }

    // WORKED_HOURS non-threshold (DAY_LIST / DAY_TYPE / unsupported valueType): all-or-nothing day gate.
    return { kind: 'FILTER', op: 'GATE', condition, input, resultIntervals: [], resultHours: 0 };
}

/** Builds the linear chain for a rule: `BASE → stage → … → RuleAstNode`. */
export function buildRuleAst(rule: HourCategorizationRule): RuleAstNode {
    let input: StageNode = { kind: 'BASE' };

    for (const condition of rule.conditions) {
        const stage = buildStage(condition, input);
        if (stage) input = stage;
    }

    return { kind: 'RULE', ruleId: rule.id, child: input, resultIntervals: [], resultHours: 0 };
}
