package app.voltplan.cable.ui.bom

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.voltplan.cable.CableApplication
import app.voltplan.cable.analytics.Analytics
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

data class BomUiState(
    val systemName: String = "",
    val sections: List<BomSection> = emptyList(),
    /** componentId -> set of completed logical ids */
    val completed: Map<String, Set<String>> = emptyMap(),
    val itemCount: Int = 0,
)

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

    val state: StateFlow<BomUiState> = combine(
        repo.observeSystem(systemId),
        repo.observeLoads(systemId),
        repo.observeBatteries(systemId),
        repo.observeChargers(systemId),
        app.settings.unitSystem,
    ) { system, loads, batteries, chargers, unit ->
        val sections = BomBuilder.build(app, loads, batteries, chargers, unit)
        val completed = buildMap {
            loads.forEach { put(it.id, it.bomCompletedItemIDs.toSet()) }
            batteries.forEach { put(it.id, it.bomCompletedItemIDs.toSet()) }
            chargers.forEach { put(it.id, it.bomCompletedItemIDs.toSet()) }
        }
        BomUiState(system?.name ?: "", sections, completed, sections.sumOf { it.items.size })
    }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), BomUiState())

    fun isCompleted(item: BomItem, completed: Map<String, Set<String>>): Boolean =
        item.storageKeys.all { (compId, logical) -> completed[compId]?.contains(logical) == true }

    fun toggle(item: BomItem) {
        val current = state.value.completed
        val makeComplete = !isCompleted(item, current)
        viewModelScope.launch {
            for ((compId, logical) in item.storageKeys) {
                val load = repo.getLoad(compId)
                if (load != null) {
                    repo.upsertLoad(load.copy(bomCompletedItemIDs = toggleSet(load.bomCompletedItemIDs, logical, makeComplete)))
                    continue
                }
                val battery = repo.getBattery(compId)
                if (battery != null) {
                    repo.upsertBattery(battery.copy(bomCompletedItemIDs = toggleSet(battery.bomCompletedItemIDs, logical, makeComplete)))
                    continue
                }
                val charger = repo.getCharger(compId)
                if (charger != null) {
                    repo.upsertCharger(charger.copy(bomCompletedItemIDs = toggleSet(charger.bomCompletedItemIDs, logical, makeComplete)))
                }
            }
        }
    }

    fun markComplete(item: BomItem) {
        val current = state.value.completed
        if (isCompleted(item, current)) return
        toggle(item)
    }

    fun logItemTapped(item: BomItem) {
        val dest = item.destination
        val url = dest.toUrl()
        val domain = url?.let { runCatching { android.net.Uri.parse(it).host }.getOrNull() } ?: "unknown"
        Analytics.log(
            "BOM Item Tapped",
            mapOf(
                "item" to item.title,
                "category" to item.category.name.lowercase(),
                "is_affiliate" to dest.isAffiliate(),
                "domain" to domain,
                "system" to state.value.systemName,
            ),
        )
    }

    fun logPdfExported() {
        Analytics.log("BOM PDF Exported", mapOf("system" to state.value.systemName, "item_count" to state.value.itemCount))
    }

    private fun toggleSet(list: List<String>, value: String, add: Boolean): List<String> {
        val set = list.toMutableSet()
        if (add) set.add(value) else set.remove(value)
        return set.toList()
    }
}
