package llc.arma.ble.app.ui.screen.connection

import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.BaseViewModel
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.inspection.beacon.BeaconContract
import llc.arma.ble.app.ui.screen.inspection.host.HostContract
import llc.arma.ble.app.ui.screen.inspection.thermometer.ThermometerContract
import llc.arma.ble.domain.usecase.GetBleBySerial
import javax.inject.Inject

@HiltViewModel
class ConnectionViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    private val getBleBySerial: GetBleBySerial,
) : BaseViewModel<ConnectionContract.State, ConnectionContract.Event, ConnectionContract.Effect>() {

    init {
        refreshBle()
    }

    override fun setInitialState() = ConnectionContract.State.Loading

    override fun handleEvents(event: ConnectionContract.Event) {
        when(event){
            is ConnectionContract.Event.OnBeaconNavigationEvent -> reduce(viewState.value, event)
            is ConnectionContract.Event.OnHostNavigationEvent -> reduce(viewState.value, event)
            is ConnectionContract.Event.OnNavigateUp -> reduce(viewState.value, event)
            is ConnectionContract.Event.OnThermometerNavigationEvent -> reduce(viewState.value, event)
            is ConnectionContract.Event.RefreshBle -> reduce(viewState.value, event)
            is ConnectionContract.Event.OnAccelNavigationEvent -> reduce(viewState.value, event)
        }
    }

    private fun reduce(
        state: ConnectionContract.State,
        event: ConnectionContract.Event.OnHostNavigationEvent
    ) {
        when(event.event){
            HostContract.Effect.Navigation.NavigateUp -> {
                setEffect {
                    ConnectionContract.Effect.Navigation.NavigateUp
                }
            }
            HostContract.Effect.Navigation.NavigateToChangePassword -> {
                setEffect {
                    ConnectionContract.Effect.Navigation.NavigateToChangePassword(savedStateHandle.get<String>("serial")!!)
                }
            }

            is HostContract.Effect.Navigation.NavigateToHostHistory -> {
                setEffect {
                    ConnectionContract.Effect.InnerNavigation.NavigateToHostHistory(
                        event.event.ble
                    )
                }
            }

            is HostContract.Effect.Navigation.NavigateToBleTable -> {
                setEffect {
                    ConnectionContract.Effect.InnerNavigation.NavigateHostToBleTable(
                        event.event.serial
                    )
                }
            }
        }
    }

    private fun reduce(
        state: ConnectionContract.State,
        event: ConnectionContract.Event.OnBeaconNavigationEvent
    ) {
        when(event.event){
            BeaconContract.Effect.Navigation.NavigateUp -> {
                setEffect {
                    ConnectionContract.Effect.Navigation.NavigateUp
                }
            }
            BeaconContract.Effect.Navigation.NavigateToChangePassword -> {
                setEffect {
                    ConnectionContract.Effect.Navigation.NavigateToChangePassword(savedStateHandle.get<String>("serial")!!)
                }
            }
        }
    }

    private fun reduce(
        state: ConnectionContract.State,
        event: ConnectionContract.Event.OnThermometerNavigationEvent
    ) {
        when(event.event){
            ThermometerContract.Effect.Navigation.NavigateUp -> {
                setEffect {
                    ConnectionContract.Effect.Navigation.NavigateUp
                }
            }
            ThermometerContract.Effect.Navigation.NavigateToChangePassword -> {
                setEffect {
                    ConnectionContract.Effect.Navigation.NavigateToChangePassword(savedStateHandle.get<String>("serial")!!)
                }
            }
        }
    }

    private fun reduce(
        state: ConnectionContract.State,
        event: ConnectionContract.Event.OnAccelNavigationEvent
    ) {
        when(event.event){
            AccelerometerContract.Effect.Navigation.NavigateToChangePassword -> {
                setEffect {
                    ConnectionContract.Effect.Navigation.NavigateToChangePassword(savedStateHandle.get<String>("serial")!!)
                }
            }

            is AccelerometerContract.Effect.Navigation.NavigateToAccelHistory -> {
                setEffect {
                    ConnectionContract.Effect.InnerNavigation.NavigateToAccelHistory(
                        event.event.ble,
                        event.event.accelScale,
                        event.event.accelMode,
                        event.event.fftAxis,
                        event.event.fftMode,
                        event.event.frequency
                    )
                }
            }

            is AccelerometerContract.Effect.Navigation.NavigateToAccelRealtime -> {
                setEffect {
                    ConnectionContract.Effect.InnerNavigation.NavigateToAccelRealtime(
                        event.event.ble,
                        event.event.accelScale,
                        event.event.accelMode,
                        event.event.fftAxis,
                        event.event.fftMode,
                        event.event.frequency
                    )
                }
            }
            is AccelerometerContract.Effect.Navigation.NavigateToAccelSpectre -> {
                setEffect {
                    ConnectionContract.Effect.InnerNavigation.NavigateToAccelSpectre(
                        event.event.ble,
                        event.event.accelScale,
                        event.event.accelMode,
                        event.event.fftAxis,
                        event.event.fftMode,
                        event.event.frequency
                    )
                }
            }
        }
    }

    private fun reduce(
        state: ConnectionContract.State,
        event: ConnectionContract.Event.OnNavigateUp
    ) {

        setEffect {
            ConnectionContract.Effect.Navigation.NavigateUp
        }

    }

    private fun reduce(
        state: ConnectionContract.State,
        event: ConnectionContract.Event.RefreshBle
    ) {

        refreshBle()

    }

    private fun refreshBle(){
        val serial = savedStateHandle.get<String>("serial")

        if(serial != null){

            viewModelScope.launch {

                setState {
                    ConnectionContract.State.Loading
                }

                getBleBySerial(serial).fold(
                    onSuccess = {

                        it.onEach {
                            setState {
                                ConnectionContract.State.Display(
                                    ble = it
                                )
                            }
                        }.launchIn(viewModelScope)

                    },
                    onFailure = {
                        setState {
                            ConnectionContract.State.DisplayException(it)
                        }
                    }
                )
            }
        } else {
            throw IllegalArgumentException("serial arg must not be null")
        }
    }

}