package app.voltplan.cable.library

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.ElectricalSystem
import app.voltplan.cable.data.model.PowerSourceType
import app.voltplan.cable.data.model.SavedBattery
import app.voltplan.cable.data.model.SavedCharger
import app.voltplan.cable.data.model.SavedLoad
import app.voltplan.cable.ui.systems.SystemIconMapper
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

data class LibraryUiState(
    val loading: Boolean = true,
    val error: String? = null,
    val items: List<ComponentLibraryItem> = emptyList(),
    val query: String = "",
) {
    val filtered: List<ComponentLibraryItem>
        get() {
            val q = query.trim()
            if (q.isEmpty()) return items
            return items.filter {
                it.localizedName.contains(q, ignoreCase = true) || it.name.contains(q, ignoreCase = true)
            }
        }
}

class ComponentLibraryViewModel(
    private val app: CableApplication,
    val libraryType: ComponentLibraryType = ComponentLibraryType.LOAD,
    private val libraryRepo: ComponentLibraryRepository = ComponentLibraryRepository(),
) : ViewModel() {
    private val repo = app.repository
    private val _state = MutableStateFlow(LibraryUiState())
    val state: StateFlow<LibraryUiState> = _state.asStateFlow()

    init { load() }

    fun load() {
        _state.value = _state.value.copy(loading = true, error = null)
        viewModelScope.launch {
            runCatching { libraryRepo.fetchAll(libraryType) }
                .onSuccess { _state.value = _state.value.copy(loading = false, items = it) }
                .onFailure { _state.value = _state.value.copy(loading = false, error = it.message ?: "Error") }
        }
    }

    fun refresh() = load()
    fun setQuery(q: String) { _state.value = _state.value.copy(query = q) }

    /** Returns the system to add into, creating a new one when [targetSystemId] is null. */
    private suspend fun ensureSystem(targetSystemId: String?): Pair<String, Boolean> {
        if (targetSystemId != null) return targetSystemId to false
        val name = repo.uniqueSystemName("New System")
        val system = ElectricalSystem(name = name, iconName = SystemIconMapper.iconFor(name), colorName = SystemIconMapper.colorOptions.random())
        repo.upsertSystem(system)
        Analytics.log("System Created", mapOf("name" to name, "source" to "library"))
        return system.id to true
    }

    /** Adds the chosen component as a load. Returns (via [onDone]) the system id to open, or null to just go back. */
    fun select(item: ComponentLibraryItem, targetSystemId: String?, onDone: (String?) -> Unit) {
        viewModelScope.launch {
            val (systemId, createdNewSystem) = ensureSystem(targetSystemId)

            val baseName = item.localizedName.ifBlank { "Library Load" }
            val loadName = repo.uniqueComponentName(systemId, baseName)
            val voltage = item.displayVoltage ?: 12.0
            val power = item.watt ?: (item.current?.let { it * voltage } ?: 0.0)
            val current = item.current ?: if (voltage > 0) power / voltage else 0.0
            val affiliate = item.primaryAffiliateLink

            val load = SavedLoad(
                name = loadName,
                voltage = voltage,
                current = current,
                power = power,
                length = 10.0,
                crossSection = 1.0,
                iconName = "lightbulb",
                colorName = "blue",
                isWattMode = item.watt != null,
                dutyCyclePercent = item.normalizedDutyCyclePercent ?: 100.0,
                dailyUsageHours = item.defaultDailyUsageHours ?: 1.0,
                systemId = systemId,
                remoteIconURLString = item.iconURL,
                affiliateURLString = affiliate?.url,
                affiliateCountryCode = affiliate?.country,
            )
            repo.upsertLoad(load)
            Analytics.log("Library Load Added", mapOf("id" to item.id, "name" to item.localizedName, "system" to systemId))

            onDone(if (createdNewSystem) systemId else null)
        }
    }

    /** Adds the chosen component as a battery, then opens its editor via [onDone] (systemId, batteryId). */
    fun selectBattery(item: ComponentLibraryItem, targetSystemId: String?, onDone: (String, String) -> Unit) {
        viewModelScope.launch {
            val (systemId, _) = ensureSystem(targetSystemId)
            val baseName = item.localizedName.ifBlank { "New Battery" }
            val name = repo.uniqueComponentName(systemId, baseName)
            val voltage = item.displayVoltage ?: 12.8
            val capacity = item.capacityAmpHours ?: 100.0
            val affiliate = item.primaryAffiliateLink

            val battery = SavedBattery(
                name = name,
                nominalVoltage = voltage,
                capacityAmpHours = capacity,
                chemistryRawValue = Chemistry.LIFEPO4.rawValue,
                iconName = "battery.100",
                colorName = "blue",
                systemId = systemId,
                affiliateURLString = affiliate?.url,
                affiliateCountryCode = affiliate?.country,
            )
            repo.upsertBattery(battery)
            Analytics.log("Library Battery Added", mapOf("id" to item.id, "name" to item.localizedName, "system" to systemId))

            onDone(systemId, battery.id)
        }
    }

    /** Adds the chosen component as a charger, then opens its editor via [onDone] (systemId, chargerId). */
    fun selectCharger(item: ComponentLibraryItem, targetSystemId: String?, onDone: (String, String) -> Unit) {
        viewModelScope.launch {
            val (systemId, _) = ensureSystem(targetSystemId)
            val baseName = item.localizedName.ifBlank { "New Charger" }
            val name = repo.uniqueComponentName(systemId, baseName)
            val inputVoltage = item.voltageIn ?: 230.0
            val outputVoltage = item.voltageOut ?: 14.2
            val power = item.watt ?: 0.0
            val current = item.outputCurrent ?: if (outputVoltage > 0) power / outputVoltage else 30.0
            val sourceType = chargerSourceType(item.componentCategory)
            val affiliate = item.primaryAffiliateLink

            val charger = SavedCharger(
                name = name,
                inputVoltage = inputVoltage,
                outputVoltage = outputVoltage,
                maxCurrentAmps = current,
                maxPowerWatts = power,
                iconName = sourceType.iconName,
                colorName = "orange",
                systemId = systemId,
                remoteIconURLString = item.iconURL,
                affiliateURLString = affiliate?.url,
                affiliateCountryCode = affiliate?.country,
                powerSourceType = sourceType.rawValue,
            )
            repo.upsertCharger(charger)
            Analytics.log("Library Charger Added", mapOf("id" to item.id, "name" to item.localizedName, "system" to systemId))

            onDone(systemId, charger.id)
        }
    }

    /** Maps a PocketBase `component_category` to a charger power source. */
    private fun chargerSourceType(category: String?): PowerSourceType {
        val c = category?.lowercase()?.takeUnless { it.isBlank() } ?: return PowerSourceType.SHORE
        return when {
            "solar" in c -> PowerSourceType.SOLAR
            "wind" in c -> PowerSourceType.WIND
            "dcdc" in c || "alternator" in c -> PowerSourceType.ALTERNATOR
            "generator" in c -> PowerSourceType.GENERATOR
            "mains" in c || "shore" in c -> PowerSourceType.SHORE
            else -> PowerSourceType.SHORE
        }
    }
}
