package org.nstart.dep265.requestservice.config

import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
import java.time.LocalDateTime

@Configuration
class JacksonConfig {
    /**
     * The service code still depends on Jackson 2 APIs, while the shared Boot 4 stack
     * auto-configures Jackson 3 for MVC. Keep a dedicated Jackson 2 mapper for internal
     * parsing until the module is migrated.
     */
    @Bean
    fun objectMapper(): ObjectMapper {
        return jacksonObjectMapper()
            .registerModule(JavaTimeModule())
            .findAndRegisterModules()
            .registerModule(utcLocalDateTimeModule())
    }

    private fun utcLocalDateTimeModule(): SimpleModule = SimpleModule("pcp-request-service-jackson2-utc-local-date-time")
        .addSerializer(LocalDateTime::class.java, Jackson2UtcLocalDateTimeSerializer())
        .addDeserializer(LocalDateTime::class.java, Jackson2UtcLocalDateTimeDeserializer())
}

private class Jackson2UtcLocalDateTimeSerializer : JsonSerializer<LocalDateTime>() {
    override fun serialize(value: LocalDateTime, gen: JsonGenerator, serializers: SerializerProvider) {
        gen.writeString(UtcDateTimes.format(value))
    }
}

private class Jackson2UtcLocalDateTimeDeserializer : JsonDeserializer<LocalDateTime>() {
    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)
    }
}
