package com.waytous.anticollision.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.mapbox.geojson.Point
import com.mapbox.maps.CameraOptions
import com.waytous.anticollision.BuildConfig
import com.waytous.anticollision.bean.MapDataSource
import com.waytous.anticollision.repository.MainRepository
import com.waytous.anticollision.utils.TRUCK_PATH_SOURCE
import com.waytous.anticollision.vo.VehicleLocationInfo
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flattenMerge
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import java.math.BigDecimal
import javax.inject.Inject

@HiltViewModel
class MainViewModel @Inject constructor(private val mainRepository: MainRepository) : ViewModel() {

    private val _cameraOptions = MutableStateFlow(CameraOptions.Builder()
        .center(Point.fromLngLat(BuildConfig.DEFAULT_LONGITUDE,BuildConfig.DEFAULT_LATITUDE))
        .zoom(DEFAULT_ZOOM_VALUE.toDouble())
        .build()
    )

    val cameraOptions:StateFlow<CameraOptions> = _cameraOptions

    private val _obstaclesSource = MutableStateFlow(MapDataSource())

    val obstaclesSource:StateFlow<MapDataSource> = _obstaclesSource

    private val _electronicFence = MutableStateFlow(MapDataSource())

    val electronicFence:StateFlow<MapDataSource> = _electronicFence

    private val _wetArea = MutableStateFlow(MapDataSource())

    val wetArea:StateFlow<MapDataSource> = _wetArea

    private val _laneNode = MutableStateFlow(MapDataSource())

    val laneNode:StateFlow<MapDataSource> = _laneNode

    private val _lane = MutableStateFlow(MapDataSource())

    val lane:StateFlow<MapDataSource> = _lane

    private val _runnableArea = MutableStateFlow(MapDataSource())

    val runnableArea:StateFlow<MapDataSource> = _runnableArea

    private val _dumpArea = MutableStateFlow(MapDataSource())

    val dumpArea:StateFlow<MapDataSource> = _dumpArea

    private val _diggingWorkArea = MutableStateFlow(MapDataSource())

    val diggingWorkArea:StateFlow<MapDataSource> = _diggingWorkArea

    private val _barricade = MutableStateFlow(MapDataSource())

    val barricade:StateFlow<MapDataSource> = _barricade

    private val _stationArea = MutableStateFlow(MapDataSource())

    val stationArea:StateFlow<MapDataSource> = _stationArea

    private val _parkSpot = MutableStateFlow(MapDataSource())

    val parkSpot:StateFlow<MapDataSource> = _parkSpot

    private val _staticObjects = MutableStateFlow(MapDataSource())

    val staticObjects:StateFlow<MapDataSource> = _staticObjects

    private val _truckPathSource = MutableStateFlow(MapDataSource(TRUCK_PATH_SOURCE))

    val truckPathSource:StateFlow<MapDataSource> = _truckPathSource

    init {
        viewModelScope.launch {
            mainRepository.remoteObstaclesVersion().collect{
                if (_obstaclesSource.value.version != it.version) {
                    _obstaclesSource.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteElectronicFenceVersion().collect{
                if (_electronicFence.value.version != it.version) {
                    _electronicFence.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteWetAreaVersion().collect{
                if (_wetArea.value.version != it.version) {
                    _wetArea.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteLaneNodeVersion().collect{
                if (_laneNode.value.version != it.version) {
                    _laneNode.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteLaneVersion().collect{
                if (_lane.value.version != it.version) {
                    _lane.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteRunnableAreaVersion().collect{
                if (_runnableArea.value.version != it.version) {
                    _runnableArea.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteDumpAreaVersion().collect{
                if (_dumpArea.value.version != it.version) {
                    _dumpArea.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteDiggingWorkAreaVersion().collect{
                if (_diggingWorkArea.value.version != it.version) {
                    _diggingWorkArea.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteBarricadeVersion().collect{
                if (_barricade.value.version != it.version) {
                    _barricade.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteStationAreaVersion().collect{
                if (_stationArea.value.version != it.version) {
                    _stationArea.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteParkSpotVersion().collect{
                if (_parkSpot.value.version != it.version) {
                    _parkSpot.value  = it
                }
            }
        }
        viewModelScope.launch {
            mainRepository.remoteStaticObjectsVersion().collect{
                if (_staticObjects.value.version != it.version) {
                    _staticObjects.value  = it
                }
            }
        }
        viewModelScope.launch {
            flow{
                emit(_cameraOptions.value)
            }
        }
    }

    @OptIn(ExperimentalCoroutinesApi::class)
    suspend fun loadMapDataSource() = flowOf(
        mainRepository.remoteObstaclesVersion(),
        mainRepository.remoteElectronicFenceVersion(),
        mainRepository.remoteWetAreaVersion(),
        mainRepository.remoteLaneNodeVersion(),
        mainRepository.remoteLaneVersion(),
        mainRepository.remoteRunnableAreaVersion(),
        mainRepository.remoteDumpAreaVersion(),
        mainRepository.remoteDiggingWorkAreaVersion(),
        mainRepository.remoteBarricadeVersion(),
        mainRepository.remoteStationAreaVersion(),
        mainRepository.remoteParkSpotVersion(),
        mainRepository.remoteStaticObjectsVersion(),
        flowOf(MapDataSource(TRUCK_PATH_SOURCE)),
    ).flattenMerge().stateIn(viewModelScope)

    suspend fun updateAroundVehicles(vehicleInfo:List<VehicleLocationInfo>) = flow {
        emit(vehicleInfo)
    }.flowOn(Dispatchers.IO ).stateIn(viewModelScope)

    fun updateZoom(zoom:BigDecimal){
        when{
            zoom.compareTo(MIN_ZOOM_VALUE) == -1->{
                _cameraOptions.value = _cameraOptions.value.toBuilder().zoom(MIN_ZOOM_VALUE.toDouble()).build()
            }
            zoom.compareTo(MAX_ZOOM_VALUE) == 1 ->{
                _cameraOptions.value = _cameraOptions.value.toBuilder().zoom(MAX_ZOOM_VALUE.toDouble()).build()
            }
            else ->{
                _cameraOptions.value = _cameraOptions.value.toBuilder().zoom(zoom.toDouble()).build()
            }
        }
    }

    companion object{

        val DEFAULT_ZOOM_VALUE = BigDecimal("14.0")

        val MAX_ZOOM_VALUE = BigDecimal("22.0")

        val MIN_ZOOM_VALUE = BigDecimal("8.0")
    }

}