DefaultPlayerInventoryService.kt

package io.github.lishangbu.avalon.game.capture

import io.github.lishangbu.avalon.game.entity.PlayerInventoryItem
import io.github.lishangbu.avalon.game.repository.PlayerInventoryItemRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.Instant

@Service
open class DefaultPlayerInventoryService(
    private val playerInventoryItemRepository: PlayerInventoryItemRepository,
) {
    open fun ensureAvailable(
        playerId: Long,
        itemId: Long,
        count: Int = 1,
    ) {
        val existing = requireInventoryItem(playerId, itemId)
        require(existing.quantity >= count) {
            "Item '$itemId' quantity is insufficient for player '$playerId'."
        }
    }

    @Transactional(rollbackFor = [Exception::class])
    open fun consume(
        playerId: Long,
        itemId: Long,
        count: Int = 1,
    ) {
        val existing = requireInventoryItem(playerId, itemId)
        require(existing.quantity >= count) {
            "Item '$itemId' quantity is insufficient for player '$playerId'."
        }
        playerInventoryItemRepository.save(
            PlayerInventoryItem(existing) {
                quantity = existing.quantity - count
                updatedAt = Instant.now()
            },
        )
    }

    private fun requireInventoryItem(
        playerId: Long,
        itemId: Long,
    ): PlayerInventoryItem =
        requireNotNull(
            playerInventoryItemRepository
                .findAll()
                .firstOrNull { inventoryItem ->
                    inventoryItem.playerId == playerId && inventoryItem.itemId == itemId
                },
        ) {
            "Item '$itemId' is not available for player '$playerId'."
        }
}