"""
Level progression experience curve calculation for FreeExile.
Pure mathematical 7-segment piecewise exponential formula adhering to PoE2 2026 Standards.
"""

from __future__ import annotations
import math
from dataclasses import dataclass
from typing import Dict


@dataclass(slots=True, frozen=True)
class LevelExpBenchmark:
    """Canonical mathematical experience benchmark for a specific character level."""
    level: int
    target_exp: int
    exp_to_next_level: int
    cumulative_exp: int
    death_penalty_ratio: float
    level_gap_safe_range: int = 5
    level_gap_penalty_exp: float = 0.60
    monster_benchmark_exp: int = 25


def calculate_piecewise_exp_curve() -> Dict[int, LevelExpBenchmark]:
    """Generates canonical 1-100 benchmarks across 7 progression segments.
    
    Segments:
      1: Levels 1-20 (Tutorial acceleration, < 0.1% total EXP)
      2: Levels 21-40 (Acts I-II Storyline deceleration)
      3: Levels 41-60 (Acts III-IV & Endgame prep)
      4: Levels 61-80 (Atlas T1-T10 linear slope 0.12)
      5: Levels 81-90 (Late Atlas T11-T13)
      6: Levels 91-98 (Red Maps T14-T16 steep incline)
      7: Level 99->100 (Hardcore soft-wall >= 30% of lifetime 1-98 EXP)
    """
    deltas: Dict[int, int] = {}

    # Segment 1 (1-20): Tutorial Acceleration
    for lvl in range(1, 21):
        deltas[lvl] = int(math.floor(500 * (lvl ** 2.3) + 100 * lvl))

    # Segment 2 (21-40): Acts I - II Storyline
    d20 = deltas[20]
    for lvl in range(21, 41):
        deltas[lvl] = int(math.floor(d20 * ((1 + 0.085 * (lvl - 20)) ** 2.4)))

    # Segment 3 (41-60): Acts III - IV & Endgame Prep
    d40 = deltas[40]
    for lvl in range(41, 61):
        deltas[lvl] = int(math.floor(d40 * math.exp(0.092 * (lvl - 40))))

    # Segment 4 (61-80): Early/Mid Atlas Maps (Linear slope 0.12 * d60)
    d60 = deltas[60]
    for lvl in range(61, 81):
        deltas[lvl] = int(math.floor(d60 + 0.12 * d60 * (lvl - 60)))

    # Segment 5 (81-90): Late Atlas (T11-T13)
    d80 = deltas[80]
    for lvl in range(81, 91):
        deltas[lvl] = int(math.floor(d80 * math.exp(0.145 * (lvl - 80))))

    # Segment 6 (91-98): Red Maps Steep Incline (T14-T16)
    d90 = deltas[90]
    for lvl in range(91, 99):
        deltas[lvl] = int(math.floor(d90 * math.exp(0.240 * (lvl - 90))))

    # Segment 7 (99->100): Hardcore Soft-Wall (35% of cumulative 1-98 EXP)
    sum_1_98 = sum(deltas[k] for k in range(1, 99))
    deltas[99] = int(math.floor(0.35 * sum_1_98))
    deltas[100] = 0

    benchmarks: Dict[int, LevelExpBenchmark] = {}
    current_cum = 0

    for lvl in range(1, 101):
        next_exp = deltas[lvl]

        if lvl <= 60:
            penalty = 0.0
        elif lvl <= 80:
            penalty = 0.05
        elif lvl <= 89:
            penalty = 0.10
        elif lvl <= 98:
            penalty = 0.15
        elif lvl == 99:
            penalty = 0.25
        else:
            penalty = 0.0

        benchmarks[lvl] = LevelExpBenchmark(
            level=lvl,
            target_exp=current_cum,
            exp_to_next_level=next_exp,
            cumulative_exp=current_cum,
            death_penalty_ratio=penalty,
            level_gap_safe_range=5,
            level_gap_penalty_exp=0.60,
            monster_benchmark_exp=25,
        )
        current_cum += next_exp

    return benchmarks
