package com.correx.core.events.serialization

import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerializationException
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonEncoder
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive

private object AnySerializer : KSerializer<Any> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("AnyValue")

    override fun serialize(encoder: Encoder, value: Any) {
        val jsonEncoder = encoder as? JsonEncoder
            ?: throw SerializationException("AnySerializer requires a JSON encoder")
        jsonEncoder.encodeJsonElement(value.toJsonElement())
    }

    override fun deserialize(decoder: Decoder): Any {
        val jsonDecoder = decoder as? JsonDecoder
            ?: throw SerializationException("AnySerializer requires a JSON decoder")
        return jsonDecoder.decodeJsonElement().toAny()
    }
}

private fun Any?.toJsonElement(): JsonElement = when (this) {
    null -> JsonNull
    is String -> JsonPrimitive(this)
    is Number -> JsonPrimitive(this)
    is Boolean -> JsonPrimitive(this)
    is Map<*, *> -> JsonObject(entries.associate { (k, v) -> k.toString() to v.toJsonElement() })
    is List<*> -> JsonArray(map { it.toJsonElement() })
    else -> throw SerializationException("Unsupported type: ${this::class.simpleName}")
}

private fun JsonElement.toAny(): Any = when (this) {
    is JsonNull -> throw SerializationException("null values are not supported in Map<String, Any>")
    is JsonPrimitive -> {
        val content = this.content
        when {
            content == "true" || content == "false" -> content == "true"
            content == "null" -> throw SerializationException("null values are not supported in Map<String, Any>")
            content.toDoubleOrNull() != null && content.contains('.') -> content.toDouble()
            content.toLongOrNull() != null -> content.toLong()
            else -> content // fallback to string
        }
    }
    is JsonObject -> entries.associate { (k, v) -> k to v.toAny() }
    is JsonArray -> map { it.toAny() }
}

object AnyMapSerializer : KSerializer<Map<String, Any>> {
    private val delegate = MapSerializer(String.serializer(), AnySerializer)
    override val descriptor: SerialDescriptor = delegate.descriptor

    @Suppress("UNCHECKED_CAST")
    override fun deserialize(decoder: Decoder): Map<String, Any> =
        delegate.deserialize(decoder)

    override fun serialize(encoder: Encoder, value: Map<String, Any>) =
        delegate.serialize(encoder, value)
}
