SideMutationStateApplier.kt

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

import io.github.lishangbu.avalon.game.battle.engine.core.model.AttachedEffectState
import io.github.lishangbu.avalon.game.battle.engine.core.model.SideState
import io.github.lishangbu.avalon.game.battle.engine.core.mutation.ApplySideConditionMutation
import io.github.lishangbu.avalon.game.battle.engine.core.mutation.RemoveSideConditionMutation
import io.github.lishangbu.avalon.game.battle.engine.core.type.StandardTargetSelectorIds

/**
 * side 级 mutation 写回助手。
 */
internal object SideMutationStateApplier {
    fun applyAddSideCondition(
        mutation: ApplySideConditionMutation,
        context: MutationApplicationContext,
        sides: Map<String, SideState>,
    ): Map<String, SideState> =
        updateSideTargets(mutation.target, context, sides) { side ->
            val existingState = side.conditionStates[mutation.conditionEffectId]
            val nextOrder =
                existingState?.effectOrder
                    ?: ((side.conditionStates.values.maxOfOrNull(AttachedEffectState::effectOrder) ?: 0) + 1)
            val nextState =
                AttachedEffectState(
                    effectId = mutation.conditionEffectId,
                    sourceId = mutation.sourceId,
                    duration = mutation.duration,
                    effectOrder = nextOrder,
                )
            side.copy(
                conditionStates = side.conditionStates + (mutation.conditionEffectId to nextState),
            )
        }

    fun applyRemoveSideCondition(
        mutation: RemoveSideConditionMutation,
        context: MutationApplicationContext,
        sides: Map<String, SideState>,
    ): Map<String, SideState> =
        updateSideTargets(mutation.target, context, sides) { side ->
            side.copy(conditionStates = side.conditionStates - mutation.conditionEffectId)
        }

    private fun updateSideTargets(
        selector: io.github.lishangbu.avalon.game.battle.engine.core.type.TargetSelectorId,
        context: MutationApplicationContext,
        sides: Map<String, SideState>,
        transform: (SideState) -> SideState,
    ): Map<String, SideState> {
        val targetSideIds =
            when (selector) {
                StandardTargetSelectorIds.SIDE -> listOfNotNull(context.side?.id)
                StandardTargetSelectorIds.FOE_SIDE -> listOfNotNull(context.foeSide?.id)
                else -> error("Unsupported side condition target selector '${selector.value}'.")
            }
        if (targetSideIds.isEmpty()) {
            return sides
        }
        val nextSides = sides.toMutableMap()
        targetSideIds.forEach { sideId ->
            val side = requireNotNull(nextSides[sideId]) { "Target side '$sideId' was not found." }
            nextSides[sideId] = transform(side)
        }
        return nextSides
    }
}