DailyChallengeService.kt

package delta.codecharacter.server.daily_challenge

import delta.codecharacter.dtos.ChallengeTypeDto
import delta.codecharacter.dtos.DailyChallengeGetRequestDto
import delta.codecharacter.server.daily_challenge.match.DailyChallengeMatchVerdictEnum
import delta.codecharacter.server.exception.CustomException
import delta.codecharacter.server.game.GameEntity
import delta.codecharacter.server.game.GameStatusEnum
import delta.codecharacter.server.logic.daily_challenge_score.DailyChallengeScoreAlgorithm
import delta.codecharacter.server.user.public_user.PublicUserService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Service
import java.time.Duration
import java.time.Instant
import java.util.UUID

@Service
class DailyChallengeService(
    @Autowired private val dailyChallengeRepository: DailyChallengeRepository,
    @Autowired private val publicUserService: PublicUserService,
    @Autowired private val dailyChallengeScoreAlgorithm: DailyChallengeScoreAlgorithm
) {

    @Value("\${environment.event-start-date}") private lateinit var startDate: String

    fun findNumberOfDays(): Int {
        val givenDateTime = Instant.parse(startDate)
        val nowDateTime = Instant.now()
        val period: Duration = Duration.between(givenDateTime, nowDateTime)
        return period.toDays().toInt()
    }

    fun getDailyChallengeByDate(): DailyChallengeEntity {
        val currentDailyChallenge =
            dailyChallengeRepository.findByDay(findNumberOfDays()).orElseThrow {
                throw CustomException(HttpStatus.BAD_REQUEST, "Invalid Request")
            }
        return currentDailyChallenge
    }

    fun getDailyChallengeByDateForUser(userId: UUID): DailyChallengeGetRequestDto {
        val user = publicUserService.getPublicUser(userId)
        val currentDailyChallenge = getDailyChallengeByDate()
        return DailyChallengeGetRequestDto(
            challName = currentDailyChallenge.challName,
            chall = currentDailyChallenge.chall,
            challType = currentDailyChallenge.challType,
            description = currentDailyChallenge.description,
            completionStatus = user.dailyChallengeHistory.containsKey(currentDailyChallenge.day)
        )
    }

    fun completeDailyChallenge(gameEntity: GameEntity, userId: UUID): DailyChallengeMatchVerdictEnum {
        val (_, coinsUsed, destruction, _, _) = gameEntity
        if (gameEntity.status == GameStatusEnum.EXECUTE_ERROR)
            return DailyChallengeMatchVerdictEnum.FAILURE
        val currentDailyChallenge = getDailyChallengeByDate()
        if ((
            currentDailyChallenge.challType == ChallengeTypeDto.MAP &&
                destruction > currentDailyChallenge.toleratedDestruction
            ) ||
            (
                currentDailyChallenge.challType == ChallengeTypeDto.CODE &&
                    destruction < currentDailyChallenge.toleratedDestruction
                )
        ) {
            val score =
                dailyChallengeScoreAlgorithm.getDailyChallengeScore(
                    playerCoinsUsed = coinsUsed,
                    playerDestruction = destruction,
                    dailyChallenge = currentDailyChallenge,
                )
            val updatedDailyChallenge =
                currentDailyChallenge.copy(
                    numberOfCompletions = currentDailyChallenge.numberOfCompletions + 1
                )
            dailyChallengeRepository.save(updatedDailyChallenge)
            publicUserService.updateDailyChallengeScore(userId, score, currentDailyChallenge)
            val user = publicUserService.getPublicUser(userId)
            if (user.dailyChallengeHistory.containsKey(currentDailyChallenge.day)) {
                return DailyChallengeMatchVerdictEnum.FAILURE
            }
            return DailyChallengeMatchVerdictEnum.SUCCESS
        }
        return DailyChallengeMatchVerdictEnum.FAILURE
    }
}