package com.waytous.anticollision.repository

import android.content.Context
import androidx.annotation.RequiresPermission
import androidx.room.Room
import com.blankj.utilcode.util.LogUtils
import com.waytous.anticollision.api.MapSourceService
import com.waytous.anticollision.bean.MapDataSourceWrapper
import com.waytous.anticollision.database.AppDatabase
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class MainRepository@Inject constructor(context:Context) {

    private val mapApi by lazy {
        MapSourceService.create()
    }

    private val mapDao by lazy {
        Room.databaseBuilder(context,AppDatabase::class.java,"anti_collision.db")
            .fallbackToDestructiveMigration().build()
            .mapDataSourceDao()
    }

    fun remoteObstaclesVersion(version:String = "-1") = suspend { mapApi.obstaclesVersion(version) }
        .asFlow()
        .map {source->
            LogUtils.d("remoteObstaclesVersion")
            source?.let {
                val dbSource = mapDao.findById(OBSTACLES_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = OBSTACLES_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = OBSTACLES_SOURCE })
                        LogUtils.d("remoteObstaclesVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteObstaclesVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的障碍物图层数据为空!")
        }

    fun localObstaclesVersion() = flow {
        val source = mapDao.findById(OBSTACLES_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteElectronicFenceVersion(version:String = "-1")= suspend { mapApi.electronicFenceVersion(version) }
        .asFlow()
        .map {source->

            source?.let {
                val dbSource = mapDao.findById(ELECTRONIC_FENCE_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = ELECTRONIC_FENCE_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = ELECTRONIC_FENCE_SOURCE })
                        LogUtils.d("remoteElectronicFenceVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteElectronicFenceVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的电子围栏地图数据为空!")
        }

    fun localElectronicFenceVersion() = flow {
        val source = mapDao.findById(ELECTRONIC_FENCE_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteWetAreaVersion(version:String = "-1")= suspend { mapApi.wetAreaVersion(version) }
        .asFlow()
        .map {source->
            source?.let {
                val dbSource = mapDao.findById(WET_AREA_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = WET_AREA_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = WET_AREA_SOURCE })
                        LogUtils.d("remoteWetAreaVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteWetAreaVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的湿滑区域地图数据为空!")
        }

    fun localWetAreaVersion() = flow {
        val source = mapDao.findById(WET_AREA_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteLaneNodeVersion(version:String = "-1")= suspend { mapApi.laneNodeVersion(version) }
        .asFlow()
        .map {source->
            source?.let {
                val dbSource = mapDao.findById(LANE_NODE_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = LANE_NODE_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = LANE_NODE_SOURCE })
                        LogUtils.d("remoteLaneNodeVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteLaneNodeVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的湿滑区域地图数据为空!")
        }

    fun localLaneNodeVersion() = flow {
        val source = mapDao.findById(LANE_NODE_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteLaneVersion(version:String = "-1")= suspend { mapApi.laneVersion(version) }
        .asFlow()
        .map {source->
            source?.let {
                val dbSource = mapDao.findById(LANE_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = LANE_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = LANE_SOURCE })
                        LogUtils.d("remoteLaneVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteLaneVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的车道图层地图数据为空!")
        }

    fun localLaneVersion() = flow {
        val source = mapDao.findById(LANE_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteRunnableAreaVersion(version:String = "-1")= suspend { mapApi.runnableAreaVersion(version) }
        .asFlow()
        .map {source->
            source?.let {
                val dbSource = mapDao.findById(RUNNABLE_AREA_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = RUNNABLE_AREA_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = RUNNABLE_AREA_SOURCE })
                        LogUtils.d("remoteRunnableAreaVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteRunnableAreaVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的可行使区域地图数据为空!")
        }

    fun localRunnableAreaVersion() = flow {
        val source = mapDao.findById(RUNNABLE_AREA_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteDumpAreaVersion(version:String = "-1")= suspend { mapApi.dumpAreaVersion(version) }
        .asFlow()
        .map {source->
            source?.let {
                val dbSource = mapDao.findById(DUMP_AREA_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = DUMP_AREA_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = DUMP_AREA_SOURCE })
                        LogUtils.d("remoteDumpAreaVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteDumpAreaVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的卸载区地图数据为空!")
        }

    fun localDumpAreaVersion() = flow {
        val source = mapDao.findById(DUMP_AREA_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteDiggingWorkAreaVersion(version:String = "-1")= suspend { mapApi.diggingWorkAreaVersion(version) }
        .asFlow()
        .map {source->
            source?.let {
                val dbSource = mapDao.findById(DIGGING_WORK_AREA_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = DIGGING_WORK_AREA_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = DIGGING_WORK_AREA_SOURCE })
                        LogUtils.d("remoteDiggingWorkAreaVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteDiggingWorkAreaVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的装载区地图数据为空!")
        }

    fun localDiggingAreaVersion() = flow {
        val source = mapDao.findById(DIGGING_WORK_AREA_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteBarricadeVersion(version:String = "-1")= suspend { mapApi.barricadeVersion(version) }
        .asFlow()
        .map {source->
            source?.let {
                val dbSource = mapDao.findById(BARRICADE_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = BARRICADE_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = BARRICADE_SOURCE })
                        LogUtils.d("remoteBarricadeVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteBarricadeVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的挡墙区域地图数据为空!")
        }

    fun localBarricadeVersion() = flow {
        val source = mapDao.findById(BARRICADE_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteStationAreaVersion(version:String = "-1")= suspend { mapApi.stationAreaVersion(version) }
        .asFlow()
        .map {source->
            source?.let {
                val dbSource = mapDao.findById(STATION_AREA_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = STATION_AREA_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = STATION_AREA_SOURCE })
                        LogUtils.d("remoteStationAreaVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteStationAreaVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的静态区域地图数据为空!")
        }

    fun localStationAreaVersion() = flow {
        val source = mapDao.findById(STATION_AREA_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteParkSpotVersion(version:String = "-1")= suspend { mapApi.parkSpotVersion(version) }
        .asFlow()
        .map {source->
            source?.let {
                val dbSource = mapDao.findById(PARK_SPOT_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = PARK_SPOT_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = PARK_SPOT_SOURCE })
                        LogUtils.d("remoteParkSpotVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteParkSpotVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的停车位图层地图数据为空!")
        }

    fun localParkSpotVersion() = flow {
        val source = mapDao.findById(PARK_SPOT_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    fun remoteStaticObjectsVersion(version:String = "-1")= suspend { mapApi.staticObjectsVersion(version) }
        .asFlow()
        .map {source->
            source?.let {
                val dbSource = mapDao.findById(STATIC_OBJECTS_SOURCE)
                if (dbSource == null) {
                    mapDao.insertAll(it.apply { sourceId = STATIC_OBJECTS_SOURCE })
                    MapDataSourceWrapper(it, true)
                } else {
                    if (dbSource.version != it.version) {
                        mapDao.deleteSource(dbSource)
                        mapDao.insertAll(it.apply { sourceId = STATIC_OBJECTS_SOURCE })
                        LogUtils.d("remoteStaticObjectsVersion")
                        MapDataSourceWrapper(it, true)
                    } else {
                        LogUtils.d("remoteStaticObjectsVersion")
                        MapDataSourceWrapper(it, false)
                    }
                }
            }?:throw Exception("获取到的静态区域地图数据为空!")
        }

    fun localStaticObjectsVersion() = flow {
        val source = mapDao.findById(STATIC_OBJECTS_SOURCE)
        emit( MapDataSourceWrapper(source, false))
    }

    companion object {

        private const val DUMP_AREA_SOURCE = "dumpAreaSource"

        private const val OBSTACLES_SOURCE = "obstaclesSource"

        private const val ELECTRONIC_FENCE_SOURCE = "electronicFenceSource"

        private const val WET_AREA_SOURCE = "wetAreaSource"

        private const val LANE_NODE_SOURCE = "laneNodeSource"

        private const val LANE_SOURCE = "laneSource"

        private const val RUNNABLE_AREA_SOURCE = "runnableAreaSource"

        private const val DIGGING_WORK_AREA_SOURCE = "diggingWorkAreaSource"

        private const val BARRICADE_SOURCE = "barricadeSource"

        private const val STATION_AREA_SOURCE = "stationAreaSource"

        private const val STATIC_OBJECTS_SOURCE = "staticObjectsSource"

        private const val PARK_SPOT_SOURCE = "parkSpotSource"
    }
}