package app.voltplan.cable.ui.batteries

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.voltplan.cable.CableApplication
import app.voltplan.cable.analytics.Analytics
import app.voltplan.cable.data.model.Chemistry
import app.voltplan.cable.data.model.SavedBattery
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.util.UUID
import kotlin.math.abs

data class BatteryState(
    val name: String = "New Battery",
    val chemistry: Chemistry = Chemistry.LIFEPO4,
    val nominalVoltage: Double = 12.8,
    val capacityAmpHours: Double = 100.0,
    val usableOverrideFraction: Double? = null,
    val chargeVoltage: Double = 14.4,
    val cutOffVoltage: Double = 10.8,
    val minTemp: Double = -20.0,
    val maxTemp: Double = 60.0,
    val iconName: String = "battery.100.bolt",
    val colorName: String = "blue",
    val advancedExpanded: Boolean = false,
) {
    val energyWattHours: Double get() = nominalVoltage * capacityAmpHours
    val usableFraction: Double get() = (usableOverrideFraction ?: chemistry.usableCapacityFraction).coerceIn(0.0, 1.0)
    val usableAmpHours: Double get() = capacityAmpHours * usableFraction
}

class BatteryEditorViewModel(
    app: CableApplication,
    private val systemId: String,
    batteryId: String?,
) : ViewModel() {
    private val repo = app.repository
    private var id: String = batteryId ?: UUID.randomUUID().toString()
    private val isNew = batteryId == null
    private var loggedCreate = false

    private val _state = MutableStateFlow(BatteryState())
    val state: StateFlow<BatteryState> = _state.asStateFlow()

    init {
        viewModelScope.launch {
            if (batteryId != null) {
                repo.getBattery(batteryId)?.let { b ->
                    _state.value = BatteryState(
                        name = b.name,
                        chemistry = Chemistry.fromRaw(b.chemistryRawValue),
                        nominalVoltage = b.nominalVoltage,
                        capacityAmpHours = b.capacityAmpHours,
                        usableOverrideFraction = b.usableCapacityOverrideFraction,
                        chargeVoltage = b.chargeVoltage ?: 14.4,
                        cutOffVoltage = b.cutOffVoltage ?: 10.8,
                        minTemp = b.minimumTemperatureCelsius ?: -20.0,
                        maxTemp = b.maximumTemperatureCelsius ?: 60.0,
                        iconName = b.iconName,
                        colorName = b.colorName,
                    )
                }
            } else {
                val color = repo.getSystem(systemId)?.colorName ?: "blue"
                val name = repo.uniqueComponentName(systemId, "New Battery")
                _state.value = _state.value.copy(name = name, colorName = color)
            }
            Analytics.log("Battery Editor Opened", mapOf("source" to if (isNew) "create" else "edit"))
        }
    }

    private fun update(transform: (BatteryState) -> BatteryState) {
        _state.value = transform(_state.value)
        persist()
    }

    fun setName(v: String) = update { it.copy(name = v) }
    fun setChemistry(c: Chemistry) = update { it.copy(chemistry = c) }
    fun setVoltage(v: Double) = update { it.copy(nominalVoltage = v.coerceAtLeast(0.0)) }
    fun setCapacity(v: Double) = update { it.copy(capacityAmpHours = v.coerceAtLeast(0.0)) }

    fun setUsablePercent(percent: Double) = update { s ->
        val fraction = (percent / 100.0).coerceIn(0.0, 1.0)
        // Clear the override when it matches the chemistry default.
        if (abs(fraction - s.chemistry.usableCapacityFraction) < 0.001) s.copy(usableOverrideFraction = null)
        else s.copy(usableOverrideFraction = fraction)
    }

    fun resetUsable() = update { it.copy(usableOverrideFraction = null) }

    fun setChargeVoltage(v: Double) = update { s ->
        s.copy(chargeVoltage = v.coerceAtLeast(s.cutOffVoltage))
    }

    fun setCutoff(v: Double) = update { s ->
        s.copy(cutOffVoltage = v.coerceAtMost(s.chargeVoltage))
    }

    fun setMinTemp(v: Double) = update { s -> s.copy(minTemp = v.coerceAtMost(s.maxTemp)) }
    fun setMaxTemp(v: Double) = update { s -> s.copy(maxTemp = v.coerceAtLeast(s.minTemp)) }
    fun toggleAdvanced() { _state.value = _state.value.copy(advancedExpanded = !_state.value.advancedExpanded) }
    fun setAppearance(name: String, icon: String, color: String) = update { it.copy(name = name, iconName = icon, colorName = color) }

    private fun persist() {
        val s = _state.value
        val battery = SavedBattery(
            id = id,
            name = s.name,
            nominalVoltage = s.nominalVoltage,
            capacityAmpHours = s.capacityAmpHours,
            usableCapacityOverrideFraction = s.usableOverrideFraction,
            chargeVoltage = s.chargeVoltage,
            cutOffVoltage = s.cutOffVoltage,
            minimumTemperatureCelsius = s.minTemp,
            maximumTemperatureCelsius = s.maxTemp,
            chemistryRawValue = s.chemistry.rawValue,
            iconName = s.iconName,
            colorName = s.colorName,
            systemId = systemId,
            timestamp = System.currentTimeMillis(),
        )
        viewModelScope.launch {
            repo.upsertBattery(battery)
            if (isNew && !loggedCreate) {
                loggedCreate = true
                Analytics.log("Battery Created", mapOf("name" to s.name, "voltage" to s.nominalVoltage, "capacity" to s.capacityAmpHours, "chemistry" to s.chemistry.rawValue))
            }
        }
    }
}
