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

import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
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.domain.model.BleFilter
import llc.arma.ble.domain.usecase.GetBleAroundFlow
import llc.arma.ble.domain.usecase.filter.GetFilterFlow
import llc.arma.ble.domain.usecase.filter.SaveFilter
import javax.inject.Inject

@HiltViewModel
class BleListViewModel @Inject constructor(
    private val getFilterFlow: GetFilterFlow,
    private val saveFilter: SaveFilter,
    getBleAroundFlow: GetBleAroundFlow
) : BaseViewModel<BleListContract.State, BleListContract.Event, BleListContract.Effect>() {

    init {

        viewModelScope.launch {

            var job: Job? = null

            getBleAroundFlow().fold(
                onSuccess = {
                    it.onEach {
                        setState {
                            copy(
                                connectedBleList = emptyList(),
                                bleList = it
                            )
                        }
                    }.launchIn(viewModelScope)
                },
                onFailure = {
                    throw IllegalStateException()
                }
            )

            getFilterFlow.invoke().onEach {
                setState {
                    copy(
                        bleFilter = it
                    )
                }
            }.launchIn(this)

            /*while (true) {

                job?.cancel()
                job = getBleAroundFlow().onEach {
                    it.fold(
                        onSuccess = {
                            setState {
                                copy(
                                    connectedBleList = emptyList(),
                                    bleList = it
                                )
                            }
                        },
                        onFailure = {

                        }
                    )

                }.launchIn(viewModelScope)

                delay(30_000)

            }*/

        }

    }

    override fun setInitialState(): BleListContract.State =
        BleListContract.State(emptyList(), emptyList(), BleFilter())

    override fun handleEvents(event: BleListContract.Event) {
        when(event){
            is BleListContract.Event.OnConnectToBle -> reduce(viewState.value, event)
            is BleListContract.Event.OnHideFilter -> reduce(viewState.value, event)
            is BleListContract.Event.OnMacFilterChanged -> reduce(viewState.value, event)
            is BleListContract.Event.OnNameFilterChanged -> reduce(viewState.value, event)
            is BleListContract.Event.OnResetFilter -> reduce(viewState.value, event)
            is BleListContract.Event.OnRssiRangeChanged -> reduce(viewState.value, event)
            is BleListContract.Event.OnShowFilter -> reduce(viewState.value, event)
            is BleListContract.Event.OnTypeChanged -> reduce(viewState.value, event)
            is BleListContract.Event.OnBatteryRangeChanged -> reduce(viewState.value, event)
            is BleListContract.Event.OnSortFieldChanged -> reduce(viewState.value, event)
            is BleListContract.Event.OnSortOrderChanged -> reduce(viewState.value, event)
        }
    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnConnectToBle
    ) {
        setEffect {
            BleListContract.Effect.Navigation.NavigateToBle(serial = event.bleAddress)
        }
    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnHideFilter
    ) {
        setEffect {
            BleListContract.Effect.HideFilter
        }
    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnMacFilterChanged
    ) {
        viewModelScope.launch {
            saveFilter(
                bleFilter = state.bleFilter.copy(mac = event.mac)
            )
        }
    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnSortOrderChanged
    ) {
        viewModelScope.launch {
            saveFilter(
                bleFilter = state.bleFilter.copy(sortOrder = event.order)
            )
        }
    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnSortFieldChanged
    ) {
        viewModelScope.launch {
            saveFilter(
                bleFilter = state.bleFilter.copy(sortField = event.field)
            )
        }
    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnNameFilterChanged
    ) {
        viewModelScope.launch {
            saveFilter(
                bleFilter = state.bleFilter.copy(name = event.name)
            )
        }
    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnResetFilter
    ) {

        viewModelScope.launch {

            saveFilter(BleFilter())

            setEffect {
                BleListContract.Effect.HideFilter
            }

        }

    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnRssiRangeChanged
    ) {
        viewModelScope.launch {
            saveFilter(
                bleFilter = state.bleFilter.copy(rssi = event.rssi)
            )
        }
    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnBatteryRangeChanged
    ) {
        viewModelScope.launch {
            saveFilter(
                bleFilter = state.bleFilter.copy(battery = event.battery)
            )
        }
    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnTypeChanged
    ) {
        viewModelScope.launch {
            saveFilter(
                bleFilter = state.bleFilter.copy(bleType = event.type)
            )
        }
    }

    private fun reduce(
        state: BleListContract.State,
        event: BleListContract.Event.OnShowFilter
    ) {
        setEffect {
            BleListContract.Effect.ShowFilter
        }
    }

}