/**
 * Base class for mastery evaluators. Each evaluator observes the
 * controller's state at a given {@link DecisionPoint} and returns a
 * multiplier:
 *
 *   `1.0`       → no opinion (identity)
 *   `> 1.0`     → bonus (e.g. 1.10 = +10%)
 *   `< 1.0`     → penalty (e.g. 0.95 = −5%)
 *
 * Multiple evaluators registered against the same point compose
 * multiplicatively. The composition pattern is intentionally symmetric:
 * the same curve drives both bonus and penalty regions — well-timed
 * inputs land in the bonus half, poorly-timed in the penalty half. Per the
 * project design convention the bonus side is bigger than the penalty
 * side (e.g. ±5% penalty for ~+12% bonus) — that's handled at the
 * curve-authoring level by asymmetric peak/trough heights.
 *
 * Subclasses override {@link evaluate}. They typically own an
 * `AnimationCurve` and a `flatBoost` exponent — see
 * `StrideTimingJumpEvaluator` for the canonical pattern.
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export class MasteryEvaluator {
    constructor() {
        /**
         * Human-readable identifier for telemetry (mastery score keying,
         * debugging overlays). Subclasses should set a stable string.
         * @type {string}
         */
        this.name = "MasteryEvaluator";
    }

    /**
     * @param {number} decisionPoint  one of {@link DecisionPoint}
     * @param {*} controller          the FirstPersonPlayerController
     * @param {*} runtime             per-entity runtime state
     * @returns {number}              multiplier; 1.0 = no opinion
     */
    // eslint-disable-next-line no-unused-vars
    evaluate(decisionPoint, controller, runtime) {
        return 1.0;
    }
}
