"""
CompositeDamageGoal: maximize the simplified attack-chain DPS (goals.MaxDPSGoal)
while also valuing survivability and keeping Eclipse-style long-recharge
powers usable, so the non-attack powers (resist toggles, Eclipse, ...) get
real search pressure instead of random slotting.

score = DPS
      + w_res   * mean(resistance over 8 damage types, each capped at res_cap)
      + w_def   * mean(positional defense Melee/Ranged/AoE, capped at def_cap)
      + w_regen * min(regeneration_bonus, regen_cap)
      + w_recharge_power * min(1, total_recharge_for(power) / needed)   [per listed long-recharge power]

All weights are tunable heuristics (documented, not game facts): they only
set how much mitigation the search is willing to trade against raw damage.
"""
from goals import Goal, MaxDPSGoal
from proc_rate import recharge_time_from_bonus

RES_TYPES = ["Smashing", "Lethal", "Fire", "Cold", "Energy", "Negative", "Toxic", "Psionic"]
POS_DEF = ["Melee", "Ranged", "AoE"]


class CompositeDamageGoal(Goal):
    def __init__(self, db, attack_chain_power_names, long_recharge_powers=None,
                 w_res=6.0, w_def=3.0, w_regen=0.5, res_cap=0.75, def_cap=0.45, regen_cap=2.0,
                 w_recharge_power=1.5, target_interval=90.0):
        self.name = "composite_damage"
        self.dps_goal = MaxDPSGoal(db, attack_chain_power_names)
        self.db = db
        self.long_recharge_powers = long_recharge_powers or []
        self.w_res, self.w_def, self.w_regen = w_res, w_def, w_regen
        self.res_cap, self.def_cap, self.regen_cap = res_cap, def_cap, regen_cap
        self.w_recharge_power, self.target_interval = w_recharge_power, target_interval

    def _parts(self, stats):
        dps = self.dps_goal._total_dps(stats)
        res = sum(min(stats["resistance"].get(t, 0.0), self.res_cap) for t in RES_TYPES) / len(RES_TYPES)
        dfn = sum(min(stats["defense"].get(t, 0.0), self.def_cap) for t in POS_DEF) / len(POS_DEF)
        regen = min(stats["regeneration_bonus"], self.regen_cap)
        rp = 0.0
        for name in self.long_recharge_powers:
            power = self.db.power(name)
            if not power:
                continue
            agg = stats["per_power"].get(name, {})
            local = agg.get((14, -1), {}).get("ed_value", 0.0)
            interval = recharge_time_from_bonus(power.get("base_recharge_time", 0.0) or 0.0,
                                                local + stats["global_recharge_bonus"])
            rp += min(1.0, self.target_interval / interval) if interval > 0 else 1.0
        return dps, res, dfn, regen, rp

    def score(self, stats):
        dps, res, dfn, regen, rp = self._parts(stats)
        return dps + self.w_res * res + self.w_def * dfn + self.w_regen * regen + self.w_recharge_power * rp

    def describe(self, stats):
        dps, res, dfn, regen, rp = self._parts(stats)
        return f"dps~{dps:.2f} mean_res={res*100:.1f}% pos_def={dfn*100:.1f}% regen={regen*100:.0f}% recharge_uptime_score={rp:.2f}"
