package com.waytous.anticollision.ui

import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ScreenUtils
import com.mapbox.geojson.Point
import com.mapbox.maps.CameraOptions
import com.mapbox.maps.Style
import com.mapbox.maps.ViewAnnotationAnchor
import com.mapbox.maps.extension.style.layers.properties.generated.IconAnchor
import com.mapbox.maps.extension.style.style
import com.mapbox.maps.plugin.animation.flyTo
import com.mapbox.maps.plugin.annotation.AnnotationConfig
import com.mapbox.maps.plugin.annotation.annotations
import com.mapbox.maps.plugin.annotation.generated.PointAnnotationManager
import com.mapbox.maps.plugin.annotation.generated.PointAnnotationOptions
import com.mapbox.maps.plugin.annotation.generated.createPointAnnotationManager
import com.mapbox.maps.plugin.attribution.attribution
import com.mapbox.maps.plugin.compass.compass
import com.mapbox.maps.plugin.logo.logo
import com.mapbox.maps.plugin.scalebar.scalebar
import com.mapbox.maps.viewannotation.ViewAnnotationManager
import com.mapbox.maps.viewannotation.viewAnnotationOptions
import com.waytous.anticollision.R
import com.waytous.anticollision.databinding.ActivityMainBinding
import com.waytous.anticollision.databinding.CurrentVehicleViewAnnotationLayoutBinding
import com.waytous.anticollision.databinding.LayoutMapBoxBinding
import com.waytous.anticollision.databinding.OtherVehicleViewAnnotationLayoutBinding
import com.waytous.anticollision.utils.BARRICADE_SOURCE
import com.waytous.anticollision.utils.BitmapUtils
import com.waytous.anticollision.utils.DIGGING_WORK_AREA_SOURCE
import com.waytous.anticollision.utils.DUMP_AREA_SOURCE
import com.waytous.anticollision.utils.ELECTRONIC_FENCE_SOURCE
import com.waytous.anticollision.utils.LANE_NODE_SOURCE
import com.waytous.anticollision.utils.LANE_SOURCE
import com.waytous.anticollision.utils.LATITUDE
import com.waytous.anticollision.utils.LONGITUDE
import com.waytous.anticollision.utils.MY_MAP_BOX_STYLE
import com.waytous.anticollision.utils.OBSTACLES_SOURCE
import com.waytous.anticollision.utils.PARK_SPOT_SOURCE
import com.waytous.anticollision.utils.RUNNABLE_AREA_SOURCE
import com.waytous.anticollision.utils.STATIC_OBJECTS_SOURCE
import com.waytous.anticollision.utils.STATION_AREA_SOURCE
import com.waytous.anticollision.utils.TRUCK_PATH_LAYER
import com.waytous.anticollision.utils.WET_AREA_SOURCE
import com.waytous.anticollision.utils.addBarricadeLineLayer
import com.waytous.anticollision.utils.addBarricadeSource
import com.waytous.anticollision.utils.addDiggingWorkAreaFillLayer
import com.waytous.anticollision.utils.addDiggingWorkAreaSource
import com.waytous.anticollision.utils.addDiggingWorkAreaSymbolLayer
import com.waytous.anticollision.utils.addDumpAreaFillLayer
import com.waytous.anticollision.utils.addDumpAreaSource
import com.waytous.anticollision.utils.addDumpAreaSymbolLayer
import com.waytous.anticollision.utils.addElectronicFenceFillLayer
import com.waytous.anticollision.utils.addElectronicFenceSource
import com.waytous.anticollision.utils.addElectronicFenceSymbolLayer
import com.waytous.anticollision.utils.addLaneLayer
import com.waytous.anticollision.utils.addLaneNodeCircleLayer
import com.waytous.anticollision.utils.addLaneNodeSource
import com.waytous.anticollision.utils.addLaneNodeSymbolLayer
import com.waytous.anticollision.utils.addLaneSource
import com.waytous.anticollision.utils.addObstaclesFillLayer
import com.waytous.anticollision.utils.addObstaclesSource
import com.waytous.anticollision.utils.addObstaclesSymbolLayer
import com.waytous.anticollision.utils.addParkSpotFillLayer
import com.waytous.anticollision.utils.addParkSpotSource
import com.waytous.anticollision.utils.addParkSpotSymbolLayer
import com.waytous.anticollision.utils.addRunnableAreaLayer
import com.waytous.anticollision.utils.addRunnableAreaSource
import com.waytous.anticollision.utils.addStaticObjectsFillLayer
import com.waytous.anticollision.utils.addStaticObjectsSource
import com.waytous.anticollision.utils.addStaticObjectsSymbolLayer
import com.waytous.anticollision.utils.addStationAreaFillLayer
import com.waytous.anticollision.utils.addStationAreaSource
import com.waytous.anticollision.utils.addStationAreaSymbolLayer
import com.waytous.anticollision.utils.addTruckPathLineLayer
import com.waytous.anticollision.utils.addTruckPathSource
import com.waytous.anticollision.utils.addWetAreaFillLayer
import com.waytous.anticollision.utils.addWetAreaSource
import com.waytous.anticollision.utils.addWetAreaSymbolLayer
import com.waytous.anticollision.utils.adjustLayerOrder
import com.waytous.anticollision.vo.VehicleAnnotation
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import java.math.BigDecimal
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {


    private lateinit var binding: ActivityMainBinding

    private val viewModel:MainModel by viewModels()

    @Inject
    lateinit var mapBinding:LayoutMapBoxBinding

    private val mapboxMap by lazy {
        mapBinding.mapView.getMapboxMap()
    }



    val iconCurrentNormalVehicleBitmap by lazy {
        BitmapUtils.bitmapFromDrawableRes(this, R.drawable.my_vehicle_normal)
    }

    private val iconOtherAlarmVehicleBitmap by lazy {
        BitmapUtils.bitmapFromDrawableRes(this, R.drawable.other_vehicle_normal)
    }

    private lateinit var viewAnnotationManager: ViewAnnotationManager

    private lateinit var pointAnnotationManager: PointAnnotationManager

    private val cameraOptions: CameraOptions by lazy {
        CameraOptions.Builder().center(
            Point.fromLngLat(
                LONGITUDE,
                LATITUDE
            )
        ).zoom(14.0).build()
    }

    companion object {
        private val scaleLengths = listOf(
            5,
            10,
            20,
            50,
            100,
            200,
            500,
            1000,
            2000,
            5000,
            10000,
            20000,
            50000,
            100000,
            200000,
            500000,
            1000000,
            2000000
        )
        const val MINIMUM_ZOOM_LEVEL = 11.0
        const val MAXIMUM_ZOOM_LEVEL = 26.0
        const val DEFAULT_ZOOM_LEVEL = 14.0
    }

    private fun setupMapBox() {
        LogUtils.d("setupMapBox")
        mapboxMap.setCamera(cameraOptions)
        mapBinding.zoomIn.setOnClickListener {
            val zoomLevel = BigDecimal(mapboxMap.cameraState.zoom).minus(BigDecimal(0.1.toString()))
            when (BigDecimal(MINIMUM_ZOOM_LEVEL.toString()).compareTo(zoomLevel)) {
                -1 -> {
                    mapboxMap.setCamera(CameraOptions.Builder().zoom(zoomLevel.toDouble()).build())
                }

                else -> {
                    mapboxMap.setCamera(CameraOptions.Builder().zoom(DEFAULT_ZOOM_LEVEL).build())
                }
            }
        }
        mapBinding.zoomOut.setOnClickListener {
            val zoomLevel = BigDecimal(mapboxMap.cameraState.zoom).add(BigDecimal(0.1.toString()))
            when (BigDecimal(MAXIMUM_ZOOM_LEVEL.toString()).compareTo(zoomLevel)) {
                -1 -> {
                    mapboxMap.setCamera(CameraOptions.Builder().zoom(DEFAULT_ZOOM_LEVEL).build())
                }

                else -> {
                    mapboxMap.setCamera(CameraOptions.Builder().zoom(zoomLevel.toDouble()).build())
                }
            }
            LogUtils.d("zoom out:${mapBinding.mapView.scalebar.distancePerPixel}")
        }
        mapBinding.locationTruck.setOnClickListener {
            mapboxMap.flyTo(cameraOptions)
        }
        mapboxMap.loadStyle(style(MY_MAP_BOX_STYLE) {
        }) {
            setupStyle(it)
        }
    }

    fun addTempAnnotations() {
        val otherAnnotation = VehicleAnnotation(
            "KK-01", 36, 25,
            Point.fromLngLat(LONGITUDE, LATITUDE), true
        )
        updateCurrentVehicleAnnotation(otherAnnotation)
        val otherAnnotation1 =
            VehicleAnnotation("KK-02", 24, 25, Point.fromLngLat(119.76739, 49.37722), true)
        val otherAnnotation2 =
            VehicleAnnotation("KK-03", 36, 20, Point.fromLngLat(119.75694, 49.38632), true)
        val others = listOf(otherAnnotation1, otherAnnotation2)
        addOtherVehicleAnnotations(others)
    }

    private fun initAnnotationManager() {
        viewAnnotationManager = mapBinding.mapView.viewAnnotationManager
        pointAnnotationManager =
            mapBinding.mapView.annotations.createPointAnnotationManager(
                AnnotationConfig(TRUCK_PATH_LAYER)
            )
    }

    fun updateCurrentVehicleAnnotation(otherAnnotation: VehicleAnnotation) {
        val pointAnnotationOptions: PointAnnotationOptions = PointAnnotationOptions()
            .withPoint(otherAnnotation.point)
            .withIconImage(iconCurrentNormalVehicleBitmap!!)
            .withIconSize(0.25)
            .withIconAnchor(IconAnchor.BOTTOM)
            .withDraggable(false)
        val pointAnnotation = pointAnnotationManager.create(pointAnnotationOptions)
        pointAnnotation.symbolSortKey = Double.MAX_VALUE
        val viewAnnotation = viewAnnotationManager.addViewAnnotation(
            resId = R.layout.current_vehicle_view_annotation_layout,
            options = viewAnnotationOptions {
                geometry(otherAnnotation.point)
                associatedFeatureId(pointAnnotation.featureIdentifier)
                anchor(ViewAnnotationAnchor.BOTTOM)
                offsetY((pointAnnotation.iconImageBitmap?.height!! * 0.25).toInt())
                allowOverlap(true)
            }
        )
        val binding = CurrentVehicleViewAnnotationLayoutBinding.bind(viewAnnotation)
        binding.annotationCurrentVehicleNo.text =
            getString(R.string.annotation_vehicle_no, "KK-001")
        binding.annotationCurrentVehicleSpeed.text =
            getString(R.string.annotation_vehicle_speed, 36)
    }

    fun addOtherVehicleAnnotations(others: List<VehicleAnnotation>) {
        others.forEach { vehicle ->
            val pointAnnotationOptions: PointAnnotationOptions = PointAnnotationOptions()
                .withPoint(vehicle.point)
                .withIconImage(iconOtherAlarmVehicleBitmap!!)
                .withIconSize(0.25)
                .withIconAnchor(IconAnchor.BOTTOM)
                .withDraggable(false)
            val pointAnnotation = pointAnnotationManager.create(pointAnnotationOptions)
            pointAnnotation.symbolSortKey = Double.MAX_VALUE
            val viewAnnotation = viewAnnotationManager.addViewAnnotation(
                resId = R.layout.other_vehicle_view_annotation_layout,
                options = viewAnnotationOptions {
                    geometry(vehicle.point)
                    associatedFeatureId(pointAnnotation.featureIdentifier)
                    anchor(ViewAnnotationAnchor.BOTTOM)
                    offsetY((pointAnnotation.iconImageBitmap?.height!! * 0.25).toInt())
                    allowOverlap(true)
                }
            )
            val binding = OtherVehicleViewAnnotationLayoutBinding.bind(viewAnnotation)
            binding.annotationOtherVehicleNo.text = getString(R.string.annotation_vehicle_no, vehicle.vehicleNo)
            binding.annotationOtherVehicleSpeed.text = vehicle.speed.toString()
            binding.annotationOtherVehicleDistance.text = vehicle.distance.toString()
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ScreenUtils.setFullScreen(this)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        with(mapBinding.mapView){
            logo.enabled = false
            compass.enabled = false
            attribution.enabled = false
        }
        setupMapBox()
    }

    private fun setupStyle(style: Style) {
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.CREATED) {
                viewModel.loadMapDataSource().collect {
                    when(it.sourceId){
                        OBSTACLES_SOURCE ->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addObstaclesSource(it.geojson)
                                style.addObstaclesFillLayer()
                                style.addObstaclesSymbolLayer()
                            }
                        }
                        ELECTRONIC_FENCE_SOURCE->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addElectronicFenceSource(it.geojson)
                                style.addElectronicFenceFillLayer()
                                style.addElectronicFenceSymbolLayer()
                            }
                        }
                        WET_AREA_SOURCE->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addWetAreaSource(it.geojson)
                                style.addWetAreaFillLayer()
                                style.addWetAreaSymbolLayer()
                            }
                        }
                        LANE_NODE_SOURCE->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addLaneNodeSource(it.geojson)
                                style.addLaneNodeCircleLayer()
                                style.addLaneNodeSymbolLayer()
                            }
                        }
                        LANE_SOURCE ->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addLaneSource(it.geojson)
                                style.addLaneLayer()
                            }
                        }
                        RUNNABLE_AREA_SOURCE->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addRunnableAreaSource(it.geojson)
                                style.addRunnableAreaLayer()
                            }
                        }
                        DUMP_AREA_SOURCE->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addDumpAreaSource(it.geojson)
                                style.addDumpAreaFillLayer()
                                style.addDumpAreaSymbolLayer()
                            }
                        }
                        DIGGING_WORK_AREA_SOURCE->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addDiggingWorkAreaSource(it.geojson)
                                style.addDiggingWorkAreaFillLayer()
                                style.addDiggingWorkAreaSymbolLayer()
                            }
                        }
                        BARRICADE_SOURCE->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addBarricadeSource(it.geojson)
                                style.addBarricadeLineLayer()
                            }
                        }
                        STATION_AREA_SOURCE->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addStationAreaSource(it.geojson)
                                style.addStationAreaFillLayer()
                                style.addStationAreaSymbolLayer()
                            }
                        }
                        PARK_SPOT_SOURCE->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addParkSpotSource(it.geojson)
                                style.addParkSpotFillLayer()
                                style.addParkSpotSymbolLayer()
                            }
                        }
                        STATIC_OBJECTS_SOURCE->{
                            if (it.geojson.isNotEmpty()&&it.version != "-1") {
                                style.addStaticObjectsSource(it.geojson)
                                style.addStaticObjectsFillLayer()
                                style.addStaticObjectsSymbolLayer()
                            }
                        }
                        else->{
                            style.addTruckPathSource()
                            style.addTruckPathLineLayer()
                        }

                    }
                    style.adjustLayerOrder()
                }
            }
        }
    }
}