from dataclasses import dataclass
from decimal import Decimal

from .constants import BASIC, NUTRITION_POLICY_KEY, NUTRITION_POLICY_VERSION
from .exceptions import UnsupportedNutritionPolicyError
from .models import PlayerNutritionProfile
from .policy import NutritionPolicyV1


@dataclass(frozen=True)
class ResolvedNutritionState:
    level: str
    multiplier: Decimal
    policy_key: str
    policy_version: str
    revision: int | None
    explicit_profile: bool


class NutritionResolver:
    """Read-only bridge from persisted Nutrition state to pure policy output.

    Training already holds the Player row lock before invoking this resolver.
    NutritionProfileService uses the same Player-first lock prefix, so a plan
    change cannot interleave with a training execution for that player.
    """

    @staticmethod
    def for_player(*, player) -> ResolvedNutritionState:
        profile = (
            PlayerNutritionProfile.objects
            .filter(player_id=player.pk)
            .only("level", "revision", "policy_key", "policy_version")
            .first()
        )
        if profile is None:
            result = NutritionPolicyV1.resolve(BASIC)
            return ResolvedNutritionState(
                level=result.level,
                multiplier=result.multiplier,
                policy_key=result.policy_key,
                policy_version=result.policy_version,
                revision=None,
                explicit_profile=False,
            )
        if (
            profile.policy_key != NUTRITION_POLICY_KEY
            or profile.policy_version != NUTRITION_POLICY_VERSION
        ):
            raise UnsupportedNutritionPolicyError(
                f"Unsupported nutrition policy {profile.policy_key}@{profile.policy_version}."
            )
        result = NutritionPolicyV1.resolve(profile.level)
        return ResolvedNutritionState(
            level=result.level,
            multiplier=result.multiplier,
            policy_key=profile.policy_key,
            policy_version=profile.policy_version,
            revision=profile.revision,
            explicit_profile=True,
        )
