package de.tsschulz.tt_tagebuch.shared.api.models

import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonEncoder
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.booleanOrNull
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.intOrNull
import kotlinx.serialization.json.longOrNull

/**
 * Akzeptiert `true`/`false`, Zahlen 0/1 und einige String-Formen – vermeidet Deserialisierungsfehler,
 * wenn die API (oder ein Proxy) Booleans als Zahl liefert.
 */
object FlexibleNullableBooleanSerializer : KSerializer<Boolean?> {
    override val descriptor: SerialDescriptor =
        PrimitiveSerialDescriptor("FlexibleNullableBoolean", PrimitiveKind.BOOLEAN)

    override fun deserialize(decoder: Decoder): Boolean? {
        val input = decoder as? JsonDecoder
            ?: error("FlexibleNullableBooleanSerializer requires JsonDecoder")
        return parseBooleanElement(input.decodeJsonElement())
    }

    private fun parseBooleanElement(element: JsonElement): Boolean? {
        if (element is JsonNull) return null
        if (element !is JsonPrimitive) return null
        element.booleanOrNull?.let { return it }
        element.intOrNull?.let { return it != 0 }
        element.longOrNull?.let { return it != 0L }
        val s = element.contentOrNull ?: return null
        return when (s.lowercase()) {
            "true", "1", "yes" -> true
            "false", "0", "no" -> false
            else -> null
        }
    }

    override fun serialize(encoder: Encoder, value: Boolean?) {
        when (encoder) {
            is JsonEncoder -> encoder.encodeJsonElement(
                if (value == null) JsonNull else JsonPrimitive(value),
            )
            else -> if (value != null) encoder.encodeBoolean(value)
        }
    }
}
