RemoveStatusBattleMutationInterceptor.kt

package io.github.lishangbu.avalon.game.battle.engine.core.runtime.flow

import io.github.lishangbu.avalon.game.battle.engine.core.constant.BattleAttributeKeys
import io.github.lishangbu.avalon.game.battle.engine.core.event.StandardHookNames
import io.github.lishangbu.avalon.game.battle.engine.core.mutation.BattleMutation
import io.github.lishangbu.avalon.game.battle.engine.core.mutation.RemoveStatusMutation
import io.github.lishangbu.avalon.game.battle.engine.core.runtime.support.MutationTargetSelectorResolver

/**
 * 主状态移除 mutation 的生命周期拦截器。
 *
 * 设计意图:
 * - 在 `RemoveStatusMutation` 真正落盘前,为目标派发一次 `on_remove_status`;
 * - 允许状态本身、能力、道具或其他挂载 effect 拦截这次清除;
 * - 保持语义明确:只有目标当前确实存在主状态时,才认为本次移除生命周期成立。
 */
class RemoveStatusBattleMutationInterceptor : BattleMutationInterceptor {
    override val order: Int = 25

    override fun supports(mutation: BattleMutation): Boolean = mutation is RemoveStatusMutation

    override fun intercept(
        context: BattleMutationInterceptionContext,
        attachedEffectProcessor: BattleAttachedEffectProcessor,
    ): BattleMutationInterceptionResult {
        val mutation =
            context.mutation as? RemoveStatusMutation
                ?: return BattleMutationInterceptionResult(context.snapshot, true, context.mutation)
        val targetUnitIds =
            MutationTargetSelectorResolver.resolve(
                mutation.target,
                BattleMutationInterceptorSupport.mutationApplicationContext(context),
            )
        var currentSnapshot = context.snapshot
        var blocked = false

        targetUnitIds.forEach { affectedTargetId ->
            val affectedUnit = currentSnapshot.units[affectedTargetId] ?: return@forEach
            val statusEffectId = affectedUnit.statusState?.effectId ?: return@forEach
            val result =
                attachedEffectProcessor.process(
                    snapshot = currentSnapshot,
                    unitId = affectedTargetId,
                    hookName = StandardHookNames.ON_REMOVE_STATUS.value,
                    targetId = affectedTargetId,
                    sourceId = context.sourceId,
                    relay = true,
                    attributes =
                        buildMap {
                            put("statusEffectId", statusEffectId)
                            BattleMutationInterceptorSupport
                                .resolveTargetRelation(currentSnapshot, context.sourceId, affectedTargetId)
                                ?.let { relation -> put(BattleAttributeKeys.TARGET_RELATION, relation) }
                        },
                )
            currentSnapshot = result.snapshot
            if (result.cancelled || result.relay == false) {
                blocked = true
            }
        }

        return BattleMutationInterceptionResult(
            snapshot = currentSnapshot,
            allowed = !blocked,
            mutation = mutation,
        )
    }
}