package org.nstart.dep265.requestservice.service

import org.nstart.dep265.requestservice.dto.GridSettingsResponseDto
import org.nstart.dep265.requestservice.dto.UpdateGridSettingsRequestDto
import org.nstart.dep265.requestservice.entity.EarthGridSettingsEntity
import org.nstart.dep265.requestservice.repository.EarthGridSettingsRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

class InvalidGridSettingsException(message: String) : IllegalArgumentException(message)

@Service
class GridSettingsService(
    private val earthGridSettingsRepository: EarthGridSettingsRepository,
) {
    @Transactional
    fun getSettings(): GridSettingsResponseDto {
        return getOrCreateSettings().toResponse()
    }

    @Transactional
    fun updateSettings(request: UpdateGridSettingsRequestDto): GridSettingsResponseDto {
        val calculationStep = request.calculationStep
            ?: throw InvalidGridSettingsException("calculationStep must be provided")
        validateCalculationStep(calculationStep)

        val settings = getOrCreateSettings()
        settings.calculationStep = calculationStep

        return earthGridSettingsRepository.save(settings).toResponse()
    }

    private fun getOrCreateSettings(): EarthGridSettingsEntity {
        return earthGridSettingsRepository.findById(EarthGridSettingsEntity.DEFAULT_SETTINGS_ID)
            .orElseGet {
                earthGridSettingsRepository.save(
                    EarthGridSettingsEntity(
                        settingsId = EarthGridSettingsEntity.DEFAULT_SETTINGS_ID,
                        calculationStep = EarthGridSettingsEntity.DEFAULT_CALCULATION_STEP,
                    )
                )
            }
    }

    private fun validateCalculationStep(calculationStep: Double) {
        if (calculationStep <= 0.0) {
            throw InvalidGridSettingsException("calculationStep must be greater than 0")
        }
    }

    private fun EarthGridSettingsEntity.toResponse(): GridSettingsResponseDto {
        return GridSettingsResponseDto(
            settingsId = settingsId,
            calculationStep = calculationStep,
        )
    }
}
