"""
Level progression types & DTOs for FreeExile.
Strictly typed immutable models adhering to PoE2 2026 Standards.
"""

from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict


@dataclass(slots=True, frozen=True)
class PlayerProgressionState:
    """Persistent and in-memory level progression state for a player character."""
    player_id: str
    level: int = 1
    current_exp: int = 0
    exp_to_next_level: int = 600
    cumulative_exp: int = 0
    lifetime_exp: int = 0
    unspent_talent_points: int = 0
    total_talent_points: int = 0
    deaths_count: int = 0


@dataclass(slots=True, frozen=True)
class ExpAwardResult:
    """Result of monster kill experience calculation and progression award."""
    exp_awarded: int
    raw_exp: int
    gap_multiplier: float
    level_gap: int
    previous_level: int
    new_level: int
    leveled_up: bool
    levels_gained: int
    current_exp: int
    exp_to_next_level: int

    @property
    def effective_exp(self) -> int:
        """Alias for exp_awarded for E2E and integration contract compatibility."""
        return self.exp_awarded

    @property
    def level_up_occurred(self) -> bool:
        """Alias for leveled_up for E2E and integration contract compatibility."""
        return self.leveled_up

    @property
    def new_exp(self) -> int:
        """Alias for current_exp for E2E and integration contract compatibility."""
        return self.current_exp


@dataclass(slots=True, frozen=True)
class DeathPenaltyResult:
    """Result of tiered death penalty calculation and safe floor application."""
    player_id: str
    level: int
    exp_lost: int
    penalty_ratio: float
    current_exp_before: int
    current_exp_after: int
    de_leveled: bool = False

    @property
    def penalty_exp_lost(self) -> int:
        """Alias for exp_lost for contract compatibility."""
        return self.exp_lost

    @property
    def penalty_percentage(self) -> float:
        """Alias for penalty_ratio for contract compatibility."""
        return self.penalty_ratio

    @property
    def new_exp(self) -> int:
        """Alias for current_exp_after for E2E test contract compatibility."""
        return self.current_exp_after


@dataclass(slots=True, frozen=True)
class LevelUpEvent:
    """Event dispatched when a character advances one or more levels."""
    player_id: str
    old_level: int
    new_level: int
    talent_points_awarded: int
    stats_gained: Dict[str, float] = field(default_factory=dict)


@dataclass(slots=True, frozen=True)
class PlayerLevelState:
    """Lightweight projection of player level and experience metrics."""
    player_id: str
    level: int
    current_exp: int
    exp_to_next_level: int
    cumulative_exp: int
    unspent_talent_points: int = 0
    total_talent_points: int = 0
    deaths_count: int = 0
