package space.nstart.pcp.pcp_coverage_scheme_service.configuration

import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.convert.converter.Converter
import org.springframework.format.FormatterRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
import tools.jackson.core.JsonGenerator
import tools.jackson.core.JsonParser
import tools.jackson.databind.DeserializationContext
import tools.jackson.databind.SerializationContext
import tools.jackson.databind.deser.std.StdDeserializer
import tools.jackson.databind.module.SimpleModule
import tools.jackson.databind.ser.std.StdSerializer
import java.time.Clock
import java.time.LocalDateTime

@Configuration
class UtcTimeConfiguration : WebMvcConfigurer {

    @Bean
    fun clock(): Clock = Clock.systemUTC()

    @Bean
    fun coverageSchemeUtcLocalDateTimeCustomizer(): JsonMapperBuilderCustomizer = JsonMapperBuilderCustomizer { builder ->
        builder.addModule(
            SimpleModule("pcp-coverage-scheme-service-utc-local-date-time")
                .addSerializer(LocalDateTime::class.java, UtcLocalDateTimeSerializer())
                .addDeserializer(LocalDateTime::class.java, UtcLocalDateTimeDeserializer())
        )
    }

    override fun addFormatters(registry: FormatterRegistry) {
        registry.addConverter(UtcLocalDateTimeQueryParamConverter())
    }
}

private class UtcLocalDateTimeQueryParamConverter : Converter<String, LocalDateTime> {
    override fun convert(source: String): LocalDateTime = UtcDateTimes.parse(source)
}

private class UtcLocalDateTimeSerializer : StdSerializer<LocalDateTime>(LocalDateTime::class.java) {
    override fun serialize(value: LocalDateTime, gen: JsonGenerator, ctxt: SerializationContext) {
        gen.writeString(UtcDateTimes.format(value))
    }
}

private class UtcLocalDateTimeDeserializer : StdDeserializer<LocalDateTime>(LocalDateTime::class.java) {
    override fun deserialize(p: JsonParser, ctxt: DeserializationContext): LocalDateTime {
        val value = p.valueAsString ?: throw IllegalArgumentException("Expected ISO-8601 UTC date-time string")
        return UtcDateTimes.parse(value)
    }
}
