package space.nstart.pcp.tle_monitoring_service.service

import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import space.nstart.pcp.tle_monitoring_service.configuration.CustomValidationException
import space.nstart.pcp.tle_monitoring_service.configuration.TlePollingProperties
import java.time.Clock
import java.time.Duration
import java.time.Instant
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.atomic.AtomicReference

data class TlePollingSettings(
    val enabled: Boolean,
    val timeoutSeconds: Long,
)

data class UpdateTlePollingSettingsRequest(
    val enabled: Boolean?,
    val timeoutSeconds: Long?,
)

@Service
class TlePollingSettingsService(
    properties: TlePollingProperties,
    private val clock: Clock = Clock.systemUTC(),
) {
    private val logger = LoggerFactory.getLogger(this::class.java)
    private val enabled = AtomicBoolean(properties.enabled)
    private val timeoutSeconds = AtomicLong(validateTimeout(properties.timeoutSeconds))
    private val lastPollStartedAt = AtomicReference<Instant?>()

    fun current(): TlePollingSettings =
        TlePollingSettings(
            enabled = enabled.get(),
            timeoutSeconds = timeoutSeconds.get(),
        )

    fun update(request: UpdateTlePollingSettingsRequest): TlePollingSettings {
        val updatedEnabled = request.enabled
            ?: throw CustomValidationException("enabled must be set")
        val updatedTimeoutSeconds = validateTimeout(
            request.timeoutSeconds ?: throw CustomValidationException("timeoutSeconds must be set")
        )

        val wasEnabled = enabled.getAndSet(updatedEnabled)
        timeoutSeconds.set(updatedTimeoutSeconds)
        if (!wasEnabled && updatedEnabled) {
            lastPollStartedAt.set(null)
        }

        val settings = current()
        logger.info(
            "TLE polling settings updated: enabled={}, timeoutSeconds={}",
            settings.enabled,
            settings.timeoutSeconds,
        )
        return settings
    }

    fun shouldStartPolling(now: Instant = clock.instant()): Boolean {
        if (!enabled.get()) {
            return false
        }

        val lastStartedAt = lastPollStartedAt.get() ?: return true
        return Duration.between(lastStartedAt, now).seconds >= timeoutSeconds.get()
    }

    fun markPollingStarted(now: Instant = clock.instant()) {
        lastPollStartedAt.set(now)
    }

    private fun validateTimeout(value: Long): Long {
        if (value <= 0) {
            throw CustomValidationException("timeoutSeconds must be greater than zero")
        }
        return value
    }
}
