package com.laseroptek.raman.ui.screens.engineer

import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.laseroptek.raman.const.VoltageTable
import com.laseroptek.raman.data.model.LifeTime
import com.laseroptek.raman.data.model.serial.EnergyMeasured
import com.laseroptek.raman.data.model.serial.LaserStatus
import com.laseroptek.raman.data.model.serial.Temperature
import com.laseroptek.raman.repository.DatabaseRepository
import com.laseroptek.raman.repository.PreferenceRepository
import com.laseroptek.raman.repository.SerialPortRepository
import com.laseroptek.raman.utils.DispatcherProvider
import com.laseroptek.raman.utils.ext.setVoltageTableValue
import com.laseroptek.raman.utils.ext.toVoltageMutableStateFlowMap
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject

@HiltViewModel
class EngineerViewModel @Inject constructor(
    private val preferenceRepository: PreferenceRepository,
    private val serialPortRepository: SerialPortRepository,
    private val databaseRepository: DatabaseRepository,
    private val dispatcherProvider: DispatcherProvider,
    private val applicationContext: Context,
) : ViewModel() {


    // isVoltageSelectedElseReptition (Engineer)
    private val _isVoltageSelectedElseReptition: MutableStateFlow<Boolean> = MutableStateFlow(true)
    val isVoltageSelectedElseReptition = _isVoltageSelectedElseReptition.asStateFlow()
    fun setIsVoltageSelectedElseReptition(value: Boolean) {
        _isVoltageSelectedElseReptition.value = value
    }

    // selectedCalibRepetitionIndex (Engineer)
    private val _selectedCalibRepetitionIndex: MutableStateFlow<Int> =  MutableStateFlow(0)
    val selectedCalibRepetitionIndex = _selectedCalibRepetitionIndex.asStateFlow()
    fun setSelectedCalibRepetitionIndex(value: Int) {
        _selectedCalibRepetitionIndex.value = value
    }

    // selectedCalibVoltageIndex (Engineer)
    private val _selectedCalibVoltageIndex: MutableStateFlow<Int> = MutableStateFlow(0)
    val selectedCalibVoltageIndex = _selectedCalibVoltageIndex.asStateFlow()
    fun setSelectedCalibVoltageIndex(value: Int) {
        _selectedCalibVoltageIndex.value = value
    }

    // selectedCalibPulseWidthIndex (Engineer)
    private val _selectedCalibPulseWidthIndex: MutableStateFlow<Int> = MutableStateFlow(0)
    val selectedCalibPulseWidthIndex = _selectedCalibPulseWidthIndex.asStateFlow()
    fun setSelectedCalibPulseWidthIndex(value: Int) {
        _selectedCalibPulseWidthIndex.value = value
    }

    // laserStatus (Engineer)
    private val _laserStatus: MutableStateFlow<LaserStatus> = MutableStateFlow(LaserStatus())
    val laserStatus = _laserStatus.asStateFlow()
    fun setLaserStatus(laserStatus: LaserStatus) {
        _laserStatus.value = laserStatus.copy()
    }

    // voltageTable (Engineer) - (PulseWidth(ms), Energy(J)) -> Voltage(V)
    private val _voltageTable: MutableStateFlow<MutableMap<Pair<Float, Float>, MutableStateFlow<Int>>> =
        VoltageTable.toVoltageMutableStateFlowMap()
    val voltageTable = _voltageTable.asStateFlow()
    fun setVoltageTable(v: MutableMap<Pair<Float, Float>, MutableStateFlow<Int>>) {
        _voltageTable.value = v
        v.forEach {
            _voltageTable.value.setVoltageTableValue(it.key, it.value.value)
        }
    }

    // load voltageTable (Engineer)
    suspend fun loadVoltageTableFromPreference() {
        val v = preferenceRepository.getVoltageTableFromPreference().first()
        val voltageTableMap = voltageTable.value
        Timber.d("Eng: loadVoltageTableFromPreference() begin")
        v.forEach { (key, value) ->
            val voltageTableVolFlow = voltageTableMap[key]
            if (voltageTableVolFlow != null) {
                voltageTableMap.setVoltageTableValue(key, value)
                //Timber.d("Eng: loadVoltageTableFromPreference() key: $key, value: $value")
            }
        }
        Timber.d("Eng: loadVoltageTableFromPreference() finish")
    }

    // save voltageTable (Engineer)
    suspend fun saveVoltageTableToPreference() {
        preferenceRepository.saveVoltageTableToPreference(
            voltageTable
                .value
                .mapValues { (_, v) -> v.value }
        )
    }

    // temperature (WRITE)
    private val _temperature_write: MutableStateFlow<Temperature> = MutableStateFlow(Temperature())
    val temperature_write = _temperature_write.asStateFlow()
    fun setTemperatureWrite(t: Temperature) {
        _temperature_write.value = t
    }

    suspend fun saveTemeratureWriteToPreference() {
        preferenceRepository.saveTemperatureWriteToPreference(temperature_write.value)
    }

    suspend fun loadTemeratureWriteFromPreference() {
        val temperatureWriteValue = preferenceRepository.getTemperatureWriteFromPreference().first()
        Timber.d("loadTemeratureWriteFromPreference: temperatureWriteValue: setTemperatureWrite($temperatureWriteValue)")
        setTemperatureWrite(temperatureWriteValue)
    }


    // lifeTime - Reserved for future use (Int[8])
    private val _lifeTime: MutableStateFlow<LifeTime> = MutableStateFlow(LifeTime())
    val lifeTime = _lifeTime.asStateFlow()
    fun setLifeTime(t: LifeTime) {
        _lifeTime.value = t
    }

    suspend fun saveLifeTimeToPreference() {
        preferenceRepository.saveLifeTimeToPreference(lifeTime.value)
    }

    suspend fun loadLifeTimeFromPreference() {
        val lifeTimeValue = preferenceRepository.getLifeTimeFromPreference().first()
        Timber.d("loadLifeTimeFromPreference: lifeTimeValue: setLifeTime($lifeTimeValue)")
        setLifeTime(lifeTimeValue)
    }


    // EnergyMeasured Write (Energy Detect - Write value from Engineer Mode)
    private val _energyMeasuredWrite: MutableStateFlow<EnergyMeasured> = MutableStateFlow(EnergyMeasured())
    val energyMeasuredWrite: MutableStateFlow<EnergyMeasured> = _energyMeasuredWrite
    fun setEnergyMeasuredWrite(m: EnergyMeasured) {
        _energyMeasuredWrite.value = m
    }

    suspend fun saveEnergyMeasuredWriteToPreference() {
        preferenceRepository.saveEnergyMeasuredWriteToPreference(energyMeasuredWrite.value)
    }
    suspend fun loadEnergyMeasuredWriteFromPreference() {
        val energyMeasuredWrite = preferenceRepository.getEnergyMeasuredWriteFromPreference().first()
        Timber.d("loadEnergyMeasuredWriteFromPreference: energyMeasuredWrite: setEnergyMeasuredWrite($energyMeasuredWrite)")
        setEnergyMeasuredWrite(energyMeasuredWrite)
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // member functions

    fun factoryDefault() {
        Timber.d("factoryDefault begins")

        val voltageTableMap = voltageTable.value
        VoltageTable.forEach { (key, value) ->
            val voltageTableVolFlow = voltageTableMap[key]
            if (voltageTableVolFlow != null) {
                voltageTableMap.setVoltageTableValue(key, value)
            }
        }

        //setQSwitch(QSwitch())

        setTemperatureWrite(Temperature())
        setLifeTime(LifeTime())
        setEnergyMeasuredWrite(EnergyMeasured())

        Timber.d("factoryDefault begins")
    }

    suspend fun saveToPreference() {
        Timber.d("saveToPreference begins")

        saveVoltageTableToPreference()
        //saveQSwitchToPreference()
        //saveGuideBeamMinToPreference()
        //saveGuideBeamMaxToPreference()
        saveTemeratureWriteToPreference()
        saveLifeTimeToPreference()
        saveEnergyMeasuredWriteToPreference()

        Timber.d("saveToPreference begins")
    }

    suspend fun loadFromPreference() {
        Timber.d("loadFromPreference begins")

        loadVoltageTableFromPreference()
        //loadQSwitchFromPreference()
        //loadGuideBeamMinFromPreference()
        //loadGuideBeamMaxFromPreference()
        loadTemeratureWriteFromPreference()
        loadLifeTimeFromPreference()
        loadEnergyMeasuredWriteFromPreference()

        Timber.d("loadFromPreference begins")
    }

    init {
        Timber.d("init begins")

        viewModelScope.launch {
            loadVoltageTableFromPreference()
            //loadQSwitchFromPreference()
            //loadGuideBeamMinFromPreference()
            //loadGuideBeamMaxFromPreference()
            loadTemeratureWriteFromPreference()
            loadLifeTimeFromPreference()
            loadEnergyMeasuredWriteFromPreference()
        }

        Timber.d("init finish")
    }
}