package app.voltplan.cable.ui.loads

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.voltplan.cable.CableApplication
import app.voltplan.cable.analytics.Analytics
import app.voltplan.cable.calc.ElectricalCalculations
import app.voltplan.cable.data.UnitSystem
import app.voltplan.cable.data.model.SavedLoad
import app.voltplan.cable.util.Fmt
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.util.UUID

data class CalcState(
    val loadName: String = "My Load",
    val voltage: Double = 12.0,
    val current: Double = 5.0,
    val power: Double = 60.0,
    val length: Double = 10.0, // metres
    val isWattMode: Boolean = false,
    val dutyCyclePercent: Double = 100.0,
    val dailyUsageHours: Double = 24.0,
    val iconName: String = "lightbulb",
    val colorName: String = "blue",
    val remoteIconURLString: String? = null,
    val affiliateURLString: String? = null,
    val affiliateCountryCode: String? = null,
    val advancedExpanded: Boolean = false,
    val bomCompletedItemIDs: List<String> = emptyList(),
) {
    val recommendedFuse: Double get() = ElectricalCalculations.recommendedFuse(current)
    val recommendedFuseFormatted: String get() = Fmt.fuse(recommendedFuse)
}

class CalculatorViewModel(
    app: CableApplication,
    private val systemId: String,
    loadId: String?,
) : ViewModel() {
    private val repo = app.repository

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

    /** Persistent identity of the load row (created lazily for new loads). */
    private var id: String = loadId ?: UUID.randomUUID().toString()
    private val isNew: Boolean = loadId == null

    init {
        if (loadId != null) {
            viewModelScope.launch {
                repo.getLoad(loadId)?.let { l ->
                    _state.value = CalcState(
                        loadName = l.name,
                        voltage = l.voltage,
                        current = l.current,
                        power = l.power,
                        length = l.length,
                        isWattMode = l.isWattMode,
                        dutyCyclePercent = l.dutyCyclePercent,
                        dailyUsageHours = l.dailyUsageHours,
                        iconName = l.iconName,
                        colorName = l.colorName,
                        remoteIconURLString = l.remoteIconURLString,
                        affiliateURLString = l.affiliateURLString,
                        affiliateCountryCode = l.affiliateCountryCode,
                        bomCompletedItemIDs = l.bomCompletedItemIDs,
                    )
                    Analytics.log("Load Opened", mapOf("mode" to mode(), "system" to systemName()))
                }
            }
        } else {
            // Mirror SystemComponentsPersistence default load values.
            _state.value = CalcState()
            persist(created = true)
        }
    }

    private fun mode() = if (_state.value.isWattMode) "watt" else "amp"
    private suspend fun systemName() = repo.getSystem(systemId)?.name ?: ""

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

    fun setVoltage(v: Double) = update { s ->
        val nv = v.coerceAtLeast(0.0)
        if (s.isWattMode) s.copy(voltage = nv, current = if (nv > 0) s.power / nv else 0.0)
        else s.copy(voltage = nv, power = nv * s.current)
    }

    fun setCurrent(a: Double) = update { s ->
        val na = a.coerceAtLeast(0.0)
        s.copy(current = na, power = s.voltage * na, isWattMode = false)
    }

    fun setPower(w: Double) = update { s ->
        val nw = w.coerceAtLeast(0.0)
        s.copy(power = nw, current = if (s.voltage > 0) nw / s.voltage else 0.0, isWattMode = true)
    }

    fun setLengthMeters(m: Double) = update { it.copy(length = m.coerceAtLeast(0.0)) }
    fun setDuty(p: Double) = update { it.copy(dutyCyclePercent = p.coerceIn(0.0, 100.0)) }
    fun setUsage(h: Double) = update { it.copy(dailyUsageHours = h.coerceIn(0.0, 24.0)) }
    fun setName(name: String) = update { it.copy(loadName = name) }
    fun toggleAdvanced() { _state.value = _state.value.copy(advancedExpanded = !_state.value.advancedExpanded) }

    fun setWattMode(enabled: Boolean) = update { s ->
        if (enabled) s.copy(isWattMode = true, current = if (s.voltage > 0) s.power / s.voltage else 0.0)
        else s.copy(isWattMode = false, power = s.voltage * s.current)
    }

    fun setAppearance(name: String, icon: String, color: String) = update {
        it.copy(loadName = name, iconName = icon, colorName = color)
    }

    private fun persist(created: Boolean) {
        val s = _state.value
        val load = SavedLoad(
            id = id,
            name = s.loadName,
            voltage = s.voltage,
            current = s.current,
            power = s.power,
            length = s.length,
            crossSection = ElectricalCalculations.recommendedCrossSection(s.length, s.current, s.voltage, UnitSystem.METRIC),
            timestamp = System.currentTimeMillis(),
            iconName = s.iconName,
            colorName = s.colorName,
            isWattMode = s.isWattMode,
            dutyCyclePercent = s.dutyCyclePercent,
            dailyUsageHours = s.dailyUsageHours,
            systemId = systemId,
            remoteIconURLString = s.remoteIconURLString,
            affiliateURLString = s.affiliateURLString,
            affiliateCountryCode = s.affiliateCountryCode,
            bomCompletedItemIDs = s.bomCompletedItemIDs,
        )
        viewModelScope.launch {
            repo.upsertLoad(load)
            if (created && isNew) {
                Analytics.log("Load Created", mapOf("name" to load.name, "system" to systemName()))
            }
        }
    }
}
