BattleSessionSetupCoordinator.kt

package io.github.lishangbu.avalon.game.battle.engine.core.session

import io.github.lishangbu.avalon.game.battle.engine.core.model.BattleLifecycle
import io.github.lishangbu.avalon.game.battle.engine.core.model.BattleType
import io.github.lishangbu.avalon.game.battle.engine.core.model.SideState
import io.github.lishangbu.avalon.game.battle.engine.core.model.UnitState
import io.github.lishangbu.avalon.game.battle.engine.core.runtime.flow.BattleRuntimeSnapshot

/**
 * BattleSession 建局与状态恢复协调器。
 *
 * 设计意图:
 * - 把 `start/register/configure/restore/settle` 这一组初始化与会话外壳管理逻辑
 *   从 `BattleSession` 主体中拆出去;
 * - 让主类把注意力放在“回合执行”和“生命周期推进”上;
 * - 保持现有公开 API 不变,仅调整内部职责分布。
 */
internal class BattleSessionSetupCoordinator(
    private val session: BattleSession,
) {
    /**
     * 导出当前可持久化状态。
     */
    fun exportState(): BattleSessionState =
        BattleSessionState(
            snapshot = session.currentSnapshot,
            pendingActions = session.pendingActions(),
            replacementRequests = session.pendingReplacementRequests(),
            resourceLedger = session.resourceLedger(),
            battleLogs = session.battleLogs(),
            eventLogs = session.eventLogs(),
        )

    /**
     * 用已持久化状态恢复当前 session。
     */
    fun restoreState(state: BattleSessionState): BattleRuntimeSnapshot {
        session.currentSnapshot = state.snapshot
        session.actionQueue.replaceAll(state.pendingActions)
        session.replacementRequests.clear()
        session.replacementRequests += state.replacementRequests
        session.resourceLedger.clear()
        session.resourceLedger += state.resourceLedger
        session.battleLogs.clear()
        session.battleLogs += state.battleLogs
        session.eventLogs.clear()
        session.eventLogs += state.eventLogs
        return session.currentSnapshot
    }

    /**
     * 启动 battle session。
     */
    fun start(): BattleRuntimeSnapshot {
        session.ensureInitializing()
        // 一旦 start,整场 battle 就从结构搭建阶段切到正式运行阶段。
        val battle =
            session.currentSnapshot.battle.copy(
                turn = 1,
                lifecycle = BattleLifecycle.RUNNING,
            )
        session.currentSnapshot = session.currentSnapshot.copy(battle = battle)
        session.recordLog("Battle ${battle.id} started at turn ${battle.turn}.")
        session.recordEvent(BattleSessionStartedPayload)
        return session.currentSnapshot
    }

    /**
     * 注册一个 side。
     */
    fun registerSide(sideId: String): BattleRuntimeSnapshot {
        session.ensureInitializing()
        val nextSides = session.currentSnapshot.sides + (sideId to SideState(id = sideId))
        session.currentSnapshot = session.currentSnapshot.copy(sides = nextSides)
        session.recordLog("Registered side $sideId.")
        session.recordEvent(BattleSessionSideRegisteredPayload(sideId = sideId))
        return session.currentSnapshot
    }

    /**
     * 配置当前 battle 的业务语义。
     */
    fun configureBattle(
        battleKind: BattleType,
        capturableSideId: String? = null,
    ): BattleRuntimeSnapshot {
        session.ensureInitializing()
        session.currentSnapshot =
            session.currentSnapshot.copy(
                battle =
                    session.currentSnapshot.battle.copy(
                        battleKind = battleKind,
                        capturableSideId = capturableSideId,
                    ),
            )
        session.recordLog("Configured battle kind=${battleKind.name} capturableSideId=$capturableSideId.")
        return session.currentSnapshot
    }

    /**
     * 注册一个单位并挂到指定 side。
     */
    fun registerUnit(
        sideId: String,
        unit: UnitState,
        active: Boolean = true,
    ): BattleRuntimeSnapshot {
        session.ensureInitializing()
        val side =
            requireNotNull(session.currentSnapshot.sides[sideId]) {
                "Side '$sideId' must be registered before units can be added."
            }
        val nextUnits = session.currentSnapshot.units + (unit.id to unit)
        val nextSide =
            if (active) {
                side.copy(
                    unitIds = (side.unitIds + unit.id).distinct(),
                    activeUnitIds = (side.activeUnitIds + unit.id).distinct(),
                )
            } else {
                side.copy(unitIds = (side.unitIds + unit.id).distinct())
            }
        session.currentSnapshot =
            session.currentSnapshot.copy(
                units = nextUnits,
                sides = session.currentSnapshot.sides + (sideId to nextSide),
            )
        session.recordLog("Registered unit ${unit.id} to side $sideId.")
        session.recordEvent(
            BattleSessionUnitRegisteredPayload(
                sideId = sideId,
                unitId = unit.id,
                active = active,
            ),
        )
        return session.currentSnapshot
    }

    /**
     * 标记当前 battle 已完成结算。
     */
    fun markSettled(): BattleRuntimeSnapshot {
        session.ensureEndedUnsettled()
        // 只有“已结束但未结算”的 battle 才允许推进到最终结算完成态。
        session.currentSnapshot =
            session.currentSnapshot.copy(
                battle =
                    session.currentSnapshot.battle.copy(
                        lifecycle = BattleLifecycle.SETTLED,
                    ),
            )
        session.recordLog("Battle settlement completed.")
        return session.currentSnapshot
    }
}