// Copyright (C) 2026 Jason M. Schwefel. All Rights Reserved.
package com.coldboreballisticsllc.scopedope.data.sensor

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.launch
import com.coldboreballisticsllc.scopedope.data.prefs.AppPreferences
import com.coldboreballisticsllc.scopedope.data.sensor.btmeter.BtmeterBt100Driver
import com.coldboreballisticsllc.scopedope.data.sensor.weatherflow.WeatherFlowTacticalDriver
import com.coldboreballisticsllc.scopedope.domain.sensor.SensorState
import com.coldboreballisticsllc.scopedope.domain.sensor.WeatherField
import com.coldboreballisticsllc.scopedope.domain.sensor.WeatherReading
import com.coldboreballisticsllc.scopedope.domain.sensor.WeatherSensorSource
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Delegates all [WeatherSensorSource] calls to whichever driver is currently selected
 * via [AppPreferences.sensorDriverId].  Switching the preference disconnects the
 * outgoing driver and hot-swaps to the incoming one without touching any other layer.
 */
@Singleton
class SensorRouter @Inject constructor(
    private val btmeter:  BtmeterBt100Driver,
    private val tactical: WeatherFlowTacticalDriver,
    private val prefs:    AppPreferences,
) : WeatherSensorSource {

    private val routerScope  = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    private val activeDriver = MutableStateFlow<WeatherSensorSource>(tactical)

    init {
        routerScope.launch {
            // conflate() drops intermediate values so rapid preference changes do not
            // interleave two concurrent swap operations.
            prefs.sensorDriverId.conflate().collect { id ->
                val next = driverFor(id)
                val prev = activeDriver.value
                if (next !== prev) {
                    prev.disconnect()
                    activeDriver.value = next
                }
            }
        }
    }

    private fun driverFor(id: String): WeatherSensorSource = when (id) {
        WeatherFlowTacticalDriver.DRIVER_ID -> tactical
        else                                -> btmeter
    }

    // ── WeatherSensorSource delegation ───────────────────────────────────────

    override val driverId:        String            get() = activeDriver.value.driverId
    override val displayName:     String            get() = activeDriver.value.displayName
    override val supportedFields: Set<WeatherField> get() = activeDriver.value.supportedFields

    override val state:    Flow<SensorState>    = activeDriver.flatMapLatest { it.state }
    override val readings: Flow<WeatherReading> = activeDriver.flatMapLatest { it.readings }

    override suspend fun connect()              = activeDriver.value.connect()
    override suspend fun disconnect()           = activeDriver.value.disconnect()
    override suspend fun snapshot(): WeatherReading? = activeDriver.value.snapshot()
}
