"""Immutable contracts for terrain-aware pace results."""

from __future__ import annotations

from dataclasses import asdict, dataclass, field
from enum import Enum
from typing import Any


class PaceEvaluationState(str, Enum):
    COMPLETE = "COMPLETE"
    UNRESOLVED = "UNRESOLVED"


@dataclass(frozen=True)
class PaceInterval:
    interval_id: str
    segment_index: int
    start_route_distance_m: float
    end_route_distance_m: float
    horizontal_distance_m: float
    start_elevation_m: float | None
    end_elevation_m: float | None
    elevation_change_m: float | None
    grade: float | None
    nominal_speed_kmh: float | None
    scenario_speed_kmh: float | None
    moving_duration_s: float | None
    cumulative_moving_duration_s: float | None
    state: PaceEvaluationState
    reason_codes: tuple[str, ...] = ()

    def to_dict(self) -> dict[str, Any]:
        return _json_value(asdict(self))


@dataclass(frozen=True)
class PacePoint:
    point_index: int
    route_distance_m: float
    cumulative_moving_seconds: float
    pace_interval_id: str | None

    def to_dict(self) -> dict[str, Any]:
        return _json_value(asdict(self))


@dataclass(frozen=True)
class PaceResult:
    route_id: str
    model_name: str
    model_version: str
    elevation_source: str
    preprocessing_policy: str
    preprocessing_distance_m: float
    scenario_name: str
    scenario_factor: float
    pause_strategy_id: str
    pause_strategy_version: str
    horizontal_distance_m: float
    ascent_m: float | None
    descent_m: float | None
    moving_time_s: float | None
    pause_time_s: float | None
    total_planned_time_s: float | None
    state: PaceEvaluationState
    reason_codes: tuple[str, ...]
    intervals: tuple[PaceInterval, ...]
    points: tuple[PacePoint, ...]
    provenance: dict[str, Any]
    runtime: dict[str, float] = field(default_factory=dict)

    @property
    def moving_seconds_by_point(self) -> dict[int, float]:
        return {point.point_index: point.cumulative_moving_seconds for point in self.points}

    @property
    def interval_by_point(self) -> dict[int, str | None]:
        return {point.point_index: point.pace_interval_id for point in self.points}

    def to_dict(self) -> dict[str, Any]:
        return _json_value(asdict(self))


def _json_value(value: Any) -> Any:
    if isinstance(value, Enum):
        return value.value
    if isinstance(value, dict):
        return {str(key): _json_value(item) for key, item in value.items()}
    if isinstance(value, (tuple, list)):
        return [_json_value(item) for item in value]
    return value
