package app.voltplan.cable.library

import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import java.util.Locale

data class AffiliateLink(val id: String, val url: String, val country: String?)

/** A component fetched from the VoltPlan PocketBase library. Mirrors `ComponentLibraryItem`. */
data class ComponentLibraryItem(
    val id: String,
    val name: String,
    val translations: Map<String, String>,
    val voltageIn: Double?,
    val voltageOut: Double?,
    val watt: Double?,
    val dutyCyclePercent: Double?,
    val defaultUtilizationFactorPercent: Double?,
    val iconURL: String?,
    val affiliateLinks: List<AffiliateLink>,
) {
    val displayVoltage: Double? get() = voltageIn ?: voltageOut

    val current: Double?
        get() {
            val v = displayVoltage ?: return null
            val w = watt ?: return null
            return if (v > 0) w / v else null
        }

    val localizedName: String get() = resolveLocalizedName(Locale.getDefault()) ?: name

    val voltageLabel: String? get() = displayVoltage?.let { String.format(Locale.US, "%.1fV", it) }
    val powerLabel: String? get() = watt?.let { String.format(Locale.US, "%.0fW", it) }
    val currentLabel: String? get() = current?.let { String.format(Locale.US, "%.1fA", it) }

    val normalizedDutyCyclePercent: Double? get() = normalizePercent(dutyCyclePercent)
    private val normalizedUtilizationFactorPercent: Double? get() = normalizePercent(defaultUtilizationFactorPercent)
    val defaultDailyUsageHours: Double? get() = normalizedUtilizationFactorPercent?.let { it / 100.0 * 24.0 }

    val primaryAffiliateLink: AffiliateLink? get() = affiliateLink(Locale.getDefault().country)

    private fun normalizePercent(value: Double?): Double? {
        if (value == null) return null
        val v = if (value <= 0) 100.0 else value
        return v.coerceIn(0.0, 100.0)
    }

    private fun resolveLocalizedName(locale: Locale): String? {
        if (translations.isEmpty()) return null
        val lang = locale.language.lowercase()
        val region = locale.country.uppercase()
        val candidates = listOfNotNull(
            if (region.isNotEmpty()) "${lang}_$region" else null,
            if (region.isNotEmpty()) "$lang-$region" else null,
            lang,
        )
        // Normalize translation keys to language/region for matching.
        val normalized = translations.mapKeys { (k, _) ->
            k.replace('-', '_').let { key ->
                val parts = key.split('_')
                if (parts.size >= 2) "${parts[0].lowercase()}_${parts[1].uppercase()}" else parts[0].lowercase()
            }
        }
        for (c in candidates) {
            val key = c.replace('-', '_')
            translations[c]?.let { return it }
            normalized[key]?.let { return it }
        }
        // Fall back to a language-only match.
        return normalized.entries.firstOrNull { it.key.startsWith(lang) }?.value
    }

    private fun affiliateLink(region: String?): AffiliateLink? {
        if (affiliateLinks.isEmpty()) return null
        val normalized = region?.trim()?.uppercase()?.takeUnless { it.isEmpty() }
        if (normalized != null) {
            affiliateLinks.firstOrNull { it.country?.uppercase() == normalized }?.let { return it }
        }
        affiliateLinks.firstOrNull { it.country == null }?.let { return it }
        return affiliateLinks.first()
    }

    companion object {
        fun from(record: PbComponentRecord, affiliateLinks: List<AffiliateLink>): ComponentLibraryItem {
            val iconUrl = record.icon?.takeIf { it.isNotBlank() }?.let {
                "$POCKETBASE_BASE/api/files/${record.collectionId}/${record.id}/$it"
            }
            return ComponentLibraryItem(
                id = record.id,
                name = record.name,
                translations = flattenTranslations(record.translations),
                voltageIn = record.voltageIn,
                voltageOut = record.voltageOut,
                watt = record.watt,
                dutyCyclePercent = record.dutyCycle,
                defaultUtilizationFactorPercent = record.defaultUtilizationFactor,
                iconURL = iconUrl,
                affiliateLinks = affiliateLinks,
            )
        }

        /** Flattens the nested translations object to locale → display name. */
        private fun flattenTranslations(element: JsonElement?): Map<String, String> {
            val obj = (element as? JsonObject) ?: return emptyMap()
            val result = LinkedHashMap<String, String>()
            for ((key, value) in obj) {
                val name = extractName(value)
                if (!name.isNullOrBlank()) result[key] = name
            }
            return result
        }

        private fun extractName(value: JsonElement): String? = when (value) {
            is JsonPrimitive -> value.contentOrNull
            is JsonObject -> value["name"]?.jsonPrimitive?.contentOrNull
                ?: value["value"]?.jsonPrimitive?.contentOrNull
                ?: value.values.firstNotNullOfOrNull { (it as? JsonPrimitive)?.contentOrNull?.takeIf { s -> s.isNotBlank() } }
            else -> null
        }
    }
}
