import time
from abc import ABC, abstractmethod

class AttributeContributor(ABC):
    @abstractmethod
    def contribute(self, state, target, final):
        """将属性加成累加到 final 字典中"""
        pass

class BaseStatsContributor(AttributeContributor):
    """基础属性（1级属性 + 等级成长 + 转生加成）"""
    def contribute(self, state, target, final):
        if target == 'player':
            entity = state['player']
            starting = state['_engine'].player_starting_stats
        else:
            entity = state['hero']
            starting = state['_engine'].hero_starting_stats

        level = entity.get('level', 1)
        rebirth = entity.get('rebirth', 0)
        engine = state['_engine']

        # 攻击力
        att_min = starting.get('attackMin', 5) + rebirth * engine.rebirth_ad_per
        att_max = starting.get('attackMax', 10) + rebirth * engine.rebirth_ad_per
        att_min += (level - 1) * engine.ad_growth_per_level
        att_max += (level - 1) * engine.ad_growth_per_level
        final['attack_min'] += att_min
        final['attack_max'] += att_max

        # 防御力
        def_min = starting.get('defenseMin', 2) + rebirth * engine.rebirth_ad_per
        def_max = starting.get('defenseMax', 5) + rebirth * engine.rebirth_ad_per
        def_min += (level - 1) * engine.ad_growth_per_level
        def_max += (level - 1) * engine.ad_growth_per_level
        final['defense_min'] += def_min
        final['defense_max'] += def_max

        # 生命值
        base_hp = starting.get('maxHp', 100) + rebirth * engine.rebirth_hp_per
        base_hp += (level - 1) * engine.hp_growth_base
        final['hp_max'] += base_hp

        # 魔法值
        base_mp = engine.rebirth_base_mp + rebirth * engine.rebirth_mp_per
        base_mp += (level - 1) * engine.mp_growth_base
        final['mp_max'] += base_mp

        # 其他基础
        final['accuracy'] += starting.get('accuracy', 1)
        final['dodge'] += starting.get('dodge', 1)
        final['game_speed'] = max(final['game_speed'], starting.get('gameSpeed', 1))
        final['exp_multiplier'] = max(final['exp_multiplier'], starting.get('expMultiplier', 1))

class GlobalEnhanceContributor(AttributeContributor):
    """金币强化的永久属性（attackEnhance, defenseEnhance 等）"""
    def contribute(self, state, target, final):
        if target == 'player':
            entity = state['player']
        else:
            entity = state['hero']
        final['attack_min'] += entity.get('attackEnhance', 0)
        final['attack_max'] += entity.get('attackEnhance', 0)
        final['defense_min'] += entity.get('defenseEnhance', 0)
        final['defense_max'] += entity.get('defenseEnhance', 0)

class EquipmentContributor(AttributeContributor):
    def contribute(self, state, target, final):
        equipment = state['equipment'][target]
        engine = state['_engine']
        attack_slots = engine.attack_slots
        defense_slots = engine.defense_slots

        for slot, item in equipment.items():
            if not item:
                continue
            if '_cached_contrib' not in item:
                self._cache_item_contrib(item, engine)
            contrib = item['_cached_contrib']
            final['attack_min'] += contrib.get('attack_min', 0)
            final['attack_max'] += contrib.get('attack_max', 0)
            final['defense_min'] += contrib.get('defense_min', 0)
            final['defense_max'] += contrib.get('defense_max', 0)
            final['hp_max'] += contrib.get('hp', 0)
            final['mp_max'] += contrib.get('mp', 0)
            final['accuracy'] += contrib.get('accuracy', 0)
            final['dodge'] += contrib.get('dodge', 0)
            final['exp_bonus'] += contrib.get('exp_bonus', 0)
            final['drop_rate'] += contrib.get('drop_rate', 0)
            final['skill_damage'] += contrib.get('skill_damage', 0)
            # 新增特殊属性累加
            final['crit_rate'] += contrib.get('crit_rate', 0)
            final['crit_damage'] += contrib.get('crit_damage', 0)
            final['lethal_rate'] += contrib.get('lethal_rate', 0)
            final['lethal_damage'] += contrib.get('lethal_damage', 0)
            final['poison_rate'] += contrib.get('poison_rate', 0)
            final['poison_damage'] += contrib.get('poison_damage', 0)

    def _cache_item_contrib(self, item, engine):
        contrib = {
            'attack_min': 0, 'attack_max': 0,
            'defense_min': 0, 'defense_max': 0,
            'hp': 0, 'mp': 0,
            'accuracy': 0, 'dodge': 0,
            'exp_bonus': 0, 'drop_rate': 0, 'skill_damage': 0,
            'crit_rate': 0, 'crit_damage': 0, 'lethal_rate': 0, 'lethal_damage': 0,
            'poison_rate': 0, 'poison_damage': 0,
        }
        contrib['crit_rate'] = item.get('critRate', 0)
        contrib['crit_damage'] = item.get('critDamage', 0)
        contrib['lethal_rate'] = item.get('lethalRate', 0)
        contrib['lethal_damage'] = item.get('lethalDamage', 0)
        contrib['poison_rate'] = item.get('poisonRate', 0)
        contrib['poison_damage'] = item.get('poisonDamage', 0)
        # 基础属性
        if 'attackMin' in item:
            contrib['attack_min'] += item.get('attackMin', 0)
            contrib['attack_max'] += item.get('attackMax', 0)
        if 'defenseMin' in item:
            contrib['defense_min'] += item.get('defenseMin', 0)
            contrib['defense_max'] += item.get('defenseMax', 0)

        # 强化等级加成
        enhance = item.get('enhanceLevel', 0)
        if enhance:
            contrib['attack_min'] += enhance
            contrib['attack_max'] += enhance
            contrib['defense_min'] += enhance
            contrib['defense_max'] += enhance

        # 特殊槽位（披风/马牌）
        if item.get('type') == 'cloak' and 'hpBonus' in item:
            contrib['hp'] += item['hpBonus']
        if item.get('type') == 'horseToken' and 'mpBonus' in item:
            contrib['mp'] += item['mpBonus']

        # 炼化属性
        refine_attrs = item.get('refine', {}).get('attrs', [])
        for ra in refine_attrs:
            atype = ra['type']
            val = ra['value']
            if atype == 'attack':
                contrib['attack_max'] += val
            elif atype == 'defense':
                contrib['defense_max'] += val
            elif atype == 'hp':
                contrib['hp'] += val
            elif atype == 'mp':
                contrib['mp'] += val
            elif atype == 'accuracy':
                contrib['accuracy'] += val
            elif atype == 'dodge':
                contrib['dodge'] += val
            elif atype == 'exp_bonus':
                contrib['exp_bonus'] += val
            elif atype == 'drop_rate':
                contrib['drop_rate'] += val
            elif atype == 'skill_damage':
                contrib['skill_damage'] += val
            elif atype == 'crit_rate':
                contrib['crit_rate'] += val
            elif atype == 'lethal_rate':
                contrib['lethal_rate'] += val
            elif atype == 'poison_rate':
                contrib['poison_rate'] += val
            elif atype == 'poison_damage':
                contrib['poison_damage'] += val

        item['_cached_contrib'] = contrib

class SetBonusContributor(AttributeContributor):
    def contribute(self, state, target, final):
        equipment = state['equipment'][target]
        engine = state['_engine']
        set_bonus = engine._get_set_bonuses(equipment)
        final['attack_min'] += set_bonus.get('attack', 0)
        final['attack_max'] += set_bonus.get('attack', 0)
        final['defense_min'] += set_bonus.get('defense', 0)
        final['defense_max'] += set_bonus.get('defense', 0)
        final['hp_max'] += set_bonus.get('hp', 0)
        final['mp_max'] += set_bonus.get('mp', 0)
        final['skill_damage'] += set_bonus.get('skillDamage', 0)

class ZodiacContributor(AttributeContributor):
    def contribute(self, state, target, final):
        if target != 'player':
            return
        zodiacs = state.get('zodiac_equipped', {})
        for z in zodiacs.values():
            final['attack_min'] += z.get('attackMin', 0)
            final['attack_max'] += z.get('attackMax', 0)
            final['defense_min'] += z.get('defenseMin', 0)
            final['defense_max'] += z.get('defenseMax', 0)
            final['hp_max'] += z.get('hpBonus', 0)
        if len(zodiacs) == 12:
            full = state['_engine'].config.get('zodiac_full_bonus', {})
            final['attack_min'] += full.get('attack', 0)
            final['attack_max'] += full.get('attack', 0)
            final['defense_min'] += full.get('defense', 0)
            final['defense_max'] += full.get('defense', 0)
            final['hp_max'] += full.get('hp', 0)

class TemporaryBuffContributor(AttributeContributor):
    def contribute(self, state, target, final):
        buffs = state.get('temporary_buffs', {})
        now = time.time()
        for buf in buffs.values():
            if buf.get('expire_time', 0) <= now:
                continue
            if buf.get('target') != target and buf.get('target') != 'both':
                continue
            attrs = buf.get('attributes', {})
            for attr, val in attrs.items():
                if attr == 'attack':
                    final['attack_min'] += val
                    final['attack_max'] += val
                elif attr == 'defense':
                    final['defense_min'] += val
                    final['defense_max'] += val
                elif attr == 'hp':
                    final['hp_max'] += val
                elif attr == 'gameSpeed':
                    final['game_speed'] += val
                elif attr == 'expMultiplier':
                    final['exp_multiplier'] += val
                elif attr == 'accuracy':
                    final['accuracy'] += val
                elif attr == 'dodge':
                    final['dodge'] += val