"""Activity kinds for a drawn route (AV-031, docs/design_reference/
activity_types_spike_v0_1.md): what a route was drawn for, and what that
decides -- the BRouter routing profile, and whether Mountain Twin has a pace
model to time it.

One registry, one place. Trekking is the default and today's behaviour: a
route saved before AV-031 (no activity stored) reads as trekking with the
hiking-mountain profile, the only profile used until then.

The activity ``trekking`` (walking with a pack) and the BRouter profile named
``trekking`` (a touring-bike profile) are different things: the touring-bike
activity is ``bike_touring``, which routes with the BRouter profile
``trekking``. Profile names never reach the interface.

Out of scope on purpose: road running -- BRouter has no running profile
(spike section a); it needs its own profile first.
"""

from __future__ import annotations

from dataclasses import dataclass


@dataclass(frozen=True)
class Activity:
    activity_id: str
    display_name_pl: str
    # "foot" or "bike": decides the interface's words (walking vs riding).
    family: str
    # The BRouter profile file on the routing server (profiles2/*.brf).
    routing_profile: str
    # True when Mountain Twin's pace engine can time this activity. The only
    # pace model is a walking one (Tobler); bikes have none yet, so their
    # days, hours and arrival times are an explicit NOT_EVALUATED, never the
    # walking pace and never BRouter's surface-blind ~22 km/h (spike e).
    pace_model_available: bool
    # The pace profile Planning starts with (mountain_twin.pace.profiles);
    # None where there is no pace model.
    default_pace_profile_id: str | None


ACTIVITIES: tuple[Activity, ...] = (
    Activity("trekking", "Trekking", "foot", "hiking-mountain", True, "normal_hiker"),
    Activity("trail_running", "Bieg górski", "foot", "hiking-mountain", True, "trail_runner"),
    Activity("road_bike", "Rower szosowy", "bike", "racebike-verylowtraffic", False, None),
    Activity("gravel", "Gravel", "bike", "gravel", False, None),
    Activity("mtb", "MTB", "bike", "MTB_SB_light", False, None),
    Activity("bike_touring", "Rower turystyczny", "bike", "trekking", False, None),
)
ACTIVITIES_BY_ID: dict[str, Activity] = {activity.activity_id: activity for activity in ACTIVITIES}
DEFAULT_ACTIVITY_ID = "trekking"

# The reason code a route gets where it cannot be timed for its activity
# (the same DayDerivationUnavailable path as a route without elevation).
PACE_MODEL_NOT_BUILT = "PACE_MODEL_NOT_BUILT_FOR_ACTIVITY"


def activity_for(activity_id: str | None) -> Activity:
    """The activity a stored or requested id names; None (a route saved
    before AV-031, or a request that names none) is trekking. An unknown id
    is an error, never silently trekking."""
    if activity_id is None:
        return ACTIVITIES_BY_ID[DEFAULT_ACTIVITY_ID]
    try:
        return ACTIVITIES_BY_ID[activity_id]
    except KeyError:
        raise ValueError(f"unknown activity: {activity_id}") from None


def pace_factor_for_activity(activity_id: str | None, pace_profile_id: str) -> float:
    """The pace factor that times a route drawn for ``activity_id`` -- or,
    for an activity with no pace model (bikes), DayDerivationUnavailable
    with PACE_MODEL_NOT_BUILT: the same explicit "cannot be timed" state a
    route without elevation gets, so every place that shows days, hours or
    arrival times already shows it as unavailable, never a walking time."""
    from mountain_twin.pace.profiles import pace_factor_for_profile

    from .day_derivation import DayDerivationUnavailable

    if not activity_for(activity_id).pace_model_available:
        raise DayDerivationUnavailable((PACE_MODEL_NOT_BUILT,), 0)
    return pace_factor_for_profile(pace_profile_id)


def activities_document() -> list[dict[str, object]]:
    """Product-facing listing for Planning's activity choice."""
    return [
        {
            "activity_id": activity.activity_id,
            "display_name_pl": activity.display_name_pl,
            "family": activity.family,
            "pace_model_available": activity.pace_model_available,
            "default_pace_profile_id": activity.default_pace_profile_id,
        }
        for activity in ACTIVITIES
    ]
