/**
 * Decision Strategy Types
 *
 * DecisionStrategy is the core abstraction for conditional rendering
 * and adaptive behavior in the v2 runtime. It replaces the experiment-based
 * filtering with a more flexible, context-aware system.
 */
import type { RuntimeContext } from '../context/types';
/**
 * Condition that checks if the current page URL matches a pattern.
 */
export interface PageUrlCondition {
    type: 'page_url';
    /** URL pattern (supports wildcards: * and **) */
    url: string;
}
/**
 * Condition that checks if the current route matches.
 */
export interface RouteCondition {
    type: 'route';
    /** Route ID from RouteFilter */
    routeId: string;
}
/**
 * Condition that checks anchor element visibility.
 */
export interface AnchorVisibleCondition {
    type: 'anchor_visible';
    /** Anchor element ID */
    anchorId: string;
    /** Required state */
    state: 'visible' | 'present' | 'absent';
}
/**
 * Condition that checks if an event occurred recently.
 */
export interface EventOccurredCondition {
    type: 'event_occurred';
    /** Event name to check */
    eventName: string;
    /** Time window in milliseconds (optional) */
    withinMs?: number;
}
/**
 * Condition that checks a state value.
 */
export interface StateEqualsCondition {
    type: 'state_equals';
    /** State key to check */
    key: string;
    /** Expected value */
    value: unknown;
}
/**
 * Condition that checks viewport size.
 */
export interface ViewportCondition {
    type: 'viewport';
    /** Minimum viewport width */
    minWidth?: number;
    /** Maximum viewport width */
    maxWidth?: number;
    /** Minimum viewport height */
    minHeight?: number;
    /** Maximum viewport height */
    maxHeight?: number;
}
/**
 * Condition that checks a session metric threshold.
 */
export interface SessionMetricCondition {
    type: 'session_metric';
    /** Metric key */
    key: string;
    /** Comparison operator */
    operator: 'gte' | 'lte' | 'eq' | 'gt' | 'lt';
    /** Threshold value */
    threshold: number;
}
/**
 * Condition that checks if an item has been dismissed.
 */
export interface DismissedCondition {
    type: 'dismissed';
    /** Item key to check */
    key: string;
    /** Invert the condition (true if NOT dismissed) */
    inverted?: boolean;
}
/**
 * Condition that checks if a cooldown is active.
 */
export interface CooldownActiveCondition {
    type: 'cooldown_active';
    /** Cooldown key to check */
    key: string;
    /** Invert the condition (true if NOT active) */
    inverted?: boolean;
}
/**
 * Condition that checks frequency limits.
 */
export interface FrequencyLimitCondition {
    type: 'frequency_limit';
    /** Frequency key to check */
    key: string;
    /** Maximum allowed count */
    limit: number;
    /** Invert the condition (true if limit NOT reached) */
    inverted?: boolean;
}
/**
 * Match operator for counter filters.
 * Exactly one of `equals` or `contains` must be specified.
 */
export interface MatchOp {
    equals?: string | number | boolean;
    contains?: string;
}
/**
 * Defines what events to count for an event_count condition.
 * Registered as an accumulator predicate at config-load time.
 */
export interface CounterDef {
    /** Event names to listen for (e.g., ["ui.click"]). ALL other filters AND with this. */
    events: string[];
    /** Prop-based filters. Keys are event prop names OR element-chain fields
     *  (tag_name, $el_text, attr__*). All entries AND together. */
    match?: Record<string, MatchOp>;
}
/**
 * Condition that checks accumulated event counts.
 * Used for behavior triggers like "visited /pricing 3+ times".
 * The key references a counter registered by the adaptive via accumulator.register().
 */
export interface EventCountCondition {
    type: 'event_count';
    /** Key referencing a callback registered via accumulator.register() */
    key: string;
    /** Comparison operator */
    operator: 'gte' | 'lte' | 'eq' | 'gt' | 'lt';
    /** Target count */
    count: number;
    /** Only count events within this time window (ms). Omit = session lifetime. */
    withinMs?: number;
    /** Inline counter definition. Defines what events to count.
     *  If omitted, predicate is pass-through (counts all events). */
    counter?: CounterDef;
}
/**
 * Union of all condition types.
 */
export type Condition = PageUrlCondition | RouteCondition | AnchorVisibleCondition | EventOccurredCondition | StateEqualsCondition | ViewportCondition | SessionMetricCondition | DismissedCondition | CooldownActiveCondition | FrequencyLimitCondition | EventCountCondition;
/**
 * Rule with conditions and output value.
 */
export interface Rule<T = unknown> {
    /** Conditions that must all be met (AND logic) */
    conditions: Condition[];
    /** Value to return if all conditions are met */
    value: T;
}
/**
 * Rule-based strategy: evaluates rules in order, returns first match.
 */
export interface RuleStrategy<T = unknown> {
    type: 'rules';
    /** Rules to evaluate in order */
    rules: Rule<T>[];
    /** Default value if no rules match */
    default: T;
}
/**
 * Score-based strategy: compares an augmented field against a threshold.
 */
export interface ScoreStrategy<T = unknown> {
    type: 'score';
    /** Field name in augmented context */
    field: string;
    /** Threshold value */
    threshold: number;
    /** Value if score >= threshold */
    above: T;
    /** Value if score < threshold */
    below: T;
}
/**
 * Model-based strategy: invokes an ML model for prediction.
 * (Phase 3 - placeholder)
 */
export interface ModelStrategy<T = unknown> {
    type: 'model';
    /** Model endpoint or ID */
    modelId: string;
    /** Input fields from context */
    inputs: string[];
    /** Mapping of model outputs to values */
    outputMapping: Record<string, T>;
    /** Default value if model call fails */
    default: T;
}
/**
 * External strategy: calls a remote endpoint for decision.
 * (Phase 3 - placeholder)
 */
export interface ExternalStrategy<T = unknown> {
    type: 'external';
    /** Endpoint URL */
    endpoint: string;
    /** HTTP method */
    method?: 'GET' | 'POST';
    /** Default value if endpoint fails */
    default: T;
    /** Timeout in milliseconds */
    timeoutMs?: number;
}
/**
 * Union of all strategy types.
 */
export type DecisionStrategy<T = unknown> = RuleStrategy<T> | ScoreStrategy<T> | ModelStrategy<T> | ExternalStrategy<T>;
/**
 * Result of evaluating a DecisionStrategy.
 */
export interface DecisionResult<T = unknown> {
    /** The decided value */
    value: T;
    /** Whether the result came from a fallback/default */
    isFallback: boolean;
    /** Debug info about which rule/condition matched */
    matchInfo?: {
        /** Strategy type that produced the result */
        strategyType: DecisionStrategy<T>['type'];
        /** Index of matched rule (for rule strategy) */
        matchedRuleIndex?: number;
        /** Conditions that were evaluated */
        evaluatedConditions?: Array<{
            condition: Condition;
            result: boolean;
        }>;
    };
}
/**
 * Route filter for tile activation.
 */
export interface RouteFilter {
    /** Routes where the tile should appear */
    include?: string[];
    /** Routes where the tile should NOT appear */
    exclude?: string[];
}
/**
 * Activation configuration for tiles.
 * Replaces the old TileExperiment type.
 */
export interface ActivationConfig {
    /** Route-based filtering */
    routes?: RouteFilter;
    /** When true, tile is hidden if none of its props.actions[] have an active triggerWhen. Default: false. */
    onlyIfPopulated?: boolean;
}
/**
 * Extended context for strategy evaluation.
 * Includes runtime references for state/event checks.
 */
export interface EvaluationContext {
    /** Runtime context snapshot */
    context: RuntimeContext;
    /** Access to state store (for dismissals, cooldowns, frequency) */
    state?: {
        isDismissed(key: string): boolean;
        isCooldownActive(key: string): boolean;
        getFrequencyCount(key: string): number;
        getSessionMetric(key: string): number;
        /** Get an arbitrary state value by key (checks session then user store). */
        getValue?(key: string): unknown;
    };
    /** Access to event bus (for event_occurred checks) */
    events?: {
        hasRecentEvent(eventName: string, withinMs: number): boolean;
    };
    /** Access to EventAccumulator for event_count conditions */
    accumulator?: {
        getCount(key: string, withinMs?: number): number;
    };
}
