"""Deterministic baseline terrain pace mathematics."""

from __future__ import annotations

import math

NOMINAL_PACE_FACTOR = 1.0
SCENARIO_PACE_FACTORS = {"FAST": 1.20, "NOMINAL": 1.00, "SLOW": 0.80}
MODEL_NAME = "normalized_tobler_style"
MODEL_VERSION = "pace_v0_1"


def nominal_terrain_speed_kmh(grade: float) -> float:
    """Return nominal terrain speed for a finite grade decimal.

    The model has no arbitrary percentage cutoff.  A grade is outside the
    numerical model domain only when the formula cannot produce a finite,
    positive speed.
    """
    if not math.isfinite(grade):
        raise ValueError("PACE_GRADE_OUT_OF_MODEL_DOMAIN")
    exponent = -3.5 * (abs(grade + 0.05) - 0.05)
    try:
        speed = 4.5 * math.exp(exponent)
    except OverflowError as exc:
        raise ValueError("PACE_GRADE_OUT_OF_MODEL_DOMAIN") from exc
    if not math.isfinite(speed) or speed <= 0:
        raise ValueError("PACE_GRADE_OUT_OF_MODEL_DOMAIN")
    return speed


def terrain_speed_kmh(grade: float, pace_factor: float = NOMINAL_PACE_FACTOR) -> float:
    """Return scenario terrain speed in km/h."""
    if not math.isfinite(pace_factor) or pace_factor <= 0:
        raise ValueError("PACE_FACTOR_INVALID")
    speed = pace_factor * nominal_terrain_speed_kmh(grade)
    if not math.isfinite(speed) or speed <= 0:
        raise ValueError("PACE_GRADE_OUT_OF_MODEL_DOMAIN")
    return speed
