package llc.arma.ble.app.ui.screen.inspection.thermometer

import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.BaseViewModel
import llc.arma.ble.app.ui.mapper.BleMapper
import llc.arma.ble.app.ui.mapper.BleViewMapper
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.usecase.WriteBle
import javax.inject.Inject

@HiltViewModel
class ThermometerViewModel @Inject constructor(
    private val bleMapper: BleMapper,
    private val bleViewMapper: BleViewMapper,
    private val writeBle: WriteBle
) : BaseViewModel<ThermometerContract.State, ThermometerContract.Event, ThermometerContract.Effect>() {

    override fun setInitialState() = ThermometerContract.State.Loading

    override fun handleEvents(event: ThermometerContract.Event) {
        when(event){
            is ThermometerContract.Event.OnNavigateUpClicked -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnBleChanged -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnSaveIntervalChanged -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnSaveIntervalEdit -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnPowerChanged -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnPowerEdit -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnSaveHistoryChanged -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnHideTemperatureHistory -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnShowTemperatureHistory -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnShowWriteBlePreview -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnHideWriteBlePreview -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnWriteBle -> reduce(viewState.value, event)
            is ThermometerContract.Event.OnChangePassword -> reduce(viewState.value, event)
        }
    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnNavigateUpClicked
    ) {
        setEffect { ThermometerContract.Effect.Navigation.NavigateUp }
    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnBleChanged
    ) {

        when(state){
            is ThermometerContract.State.Display -> setState {
                state.copy(
                    origin = Ble.Thermometer(
                        info = event.ble.info,
                        state = state.origin.state,
                        thermometerState = state.origin.thermometerState
                    )
                )
            }
            is ThermometerContract.State.Loading -> setState {
                ThermometerContract.State.Display(
                    origin = event.ble,
                    thermometer = bleMapper.map(event.ble) as BleView.Thermometer,
                    writeState = null
                )
            }
        }

    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnSaveIntervalEdit
    ) {
        setEffect {
            ThermometerContract.Effect.ShowIntervalPicker
        }
    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnSaveIntervalChanged
    ) {
        if(state is ThermometerContract.State.Display) {

            state.thermometer.thermometerState.historyInterval = event.interval

        }

        setEffect {
            ThermometerContract.Effect.HideIntervalPicker
        }

    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnPowerEdit
    ) {
        setEffect {
            ThermometerContract.Effect.ShowPowerPicker
        }
    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnPowerChanged
    ) {
        if(state is ThermometerContract.State.Display) {

            state.thermometer.state.tx = event.tx

        }

        setEffect {
            ThermometerContract.Effect.HidePowerPicker
        }

    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnSaveHistoryChanged
    ) {
        if(state is ThermometerContract.State.Display) {

            state.thermometer.thermometerState.saveHistory = event.saveHistory

        }

    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnShowTemperatureHistory
    ) {

        setEffect {
            ThermometerContract.Effect.ShowTemperatureHistory
        }

    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnHideTemperatureHistory
    ) {

        setEffect {
            ThermometerContract.Effect.HideTemperatureHistory
        }

    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnShowWriteBlePreview
    ) {

        if(state is ThermometerContract.State.Display){

            val newBle = bleViewMapper.map(state.thermometer) as Ble.Thermometer

            val writeRequest = Ble.Thermometer.WriteRequest(
                tx = if(newBle.state.tx == state.origin.state.tx) null else newBle.state.tx,
                saveHistory = if(newBle.thermometerState.saveHistory == state.origin.thermometerState.saveHistory) null else newBle.thermometerState.saveHistory,
                historyInterval = if(newBle.thermometerState.historyInterval == state.origin.thermometerState.historyInterval) null else newBle.thermometerState.historyInterval,
            )

            setState {
                state.copy(
                    writeState = ThermometerContract.State.Display.WriteState.DisplayPreview(
                        writeRequest
                    )
                )
            }

            setEffect {
                ThermometerContract.Effect.ShowWriteBle
            }

        }

    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnWriteBle
    ) {

        if(state is ThermometerContract.State.Display){

            state.writeState?.let { request ->

                if(request is ThermometerContract.State.Display.WriteState.DisplayPreview) {

                    viewModelScope.launch {

                        setState {
                            state.copy(
                                writeState = ThermometerContract.State.Display.WriteState.Writing(
                                    request.writeRequest
                                )
                            )
                        }

                        writeBle(state.thermometer.info.serial, request.writeRequest).fold(
                            onSuccess = {

                                val currentState = viewState.value

                                if(currentState is ThermometerContract.State.Display) {

                                    val newBleObject = Ble.Thermometer(
                                        info = currentState.origin.info,
                                        state = currentState.origin.state.copy(
                                            tx = request.writeRequest.tx ?: state.origin.state.tx
                                        ),
                                        thermometerState = currentState.origin.thermometerState.copy(
                                            saveHistory = request.writeRequest.saveHistory
                                                ?: currentState.origin.thermometerState.saveHistory,
                                            historyInterval = request.writeRequest.historyInterval
                                                ?: currentState.origin.thermometerState.historyInterval,
                                        )
                                    )

                                    setState {
                                        currentState.copy(
                                            origin = newBleObject,
                                            thermometer = bleMapper.map(newBleObject) as BleView.Thermometer,
                                            writeState = ThermometerContract.State.Display.WriteState.Success
                                        )
                                    }

                                }

                            },
                            onFailure = {
                                setState {
                                    state.copy(
                                        writeState = ThermometerContract.State.Display.WriteState.Failure
                                    )
                                }
                            }
                        )

                    }

                }

            }

        }

    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnHideWriteBlePreview
    ) {

        if(state is ThermometerContract.State.Display){

            setState {
                state.copy(
                    writeState = null
                )
            }

        }

        setEffect {
            ThermometerContract.Effect.HideWriteBle
        }

    }

    private fun reduce(
        state: ThermometerContract.State,
        event: ThermometerContract.Event.OnChangePassword
    ) {

        if(state is ThermometerContract.State.Display){

            setEffect {
                ThermometerContract.Effect.Navigation.NavigateToChangePassword
            }

        }

    }

}