package com.za.ui.servicing.go_to_destination

import com.amap.api.maps.model.BitmapDescriptorFactory
import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.MarkerOptions
import com.blankj.utilcode.util.ToastUtils
import com.za.base.Const
import com.za.base.IServicingVm
import com.za.base.view.LoadingManager
import com.za.bean.db.order.OrderInfo
import com.za.bean.request.UpdateTaskBean
import com.za.bean.request.UpdateTaskRequest
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.ext.getNextStatus
import com.za.ext.toJson
import com.za.net.CommonMethod
import com.za.offline.OfflineUpdateTaskBean
import com.za.service.location.ZdLocationManager
import com.za.servicing.R
import kotlinx.coroutines.flow.MutableStateFlow
import androidx.lifecycle.viewModelScope
import com.amap.api.maps.AMapUtils
import com.amap.api.services.core.LatLonPoint
import com.amap.api.services.route.BusRouteResult
import com.amap.api.services.route.DriveRouteResult
import com.amap.api.services.route.RideRouteResult
import com.amap.api.services.route.RouteSearch
import com.amap.api.services.route.WalkRouteResult
import com.blankj.utilcode.util.ActivityUtils
import com.za.common.util.ImageUtil
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale

class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestinationVm.UiState>() {
	private val _uiState = MutableStateFlow(UiState())
	val uiState get() = _uiState
	override fun updateState(uiState : UiState) {
		_uiState.value = uiState
	}

	override fun dispatch(action : Action) {
		when (action) {
			is Action.Init -> init()
			is Action.UpdateTask -> updateTask()
			is Action.UpdateState -> updateState(action.uiState)
			is Action.UploadOffline -> updateOfflineTask()
			is Action.StartTimer -> startTimer()
		}
	}

	private fun updateOfflineTask(taskRequest : UpdateTaskRequest? = null) {
		LoadingManager.showLoading()
		ZdLocationManager.getSingleLocation(success = {
			LoadingManager.hideLoading()
			val temp = taskRequest ?: UpdateTaskRequest(type = "ARRIVE_DEST",
				taskId = GlobalData.currentOrder?.taskId,
				userId = GlobalData.driverInfoBean?.userId,
				vehicleId = GlobalData.driverInfoBean?.vehicleId,
				flowType = GlobalData.currentOrder?.flowType,
				currentState = GlobalData.currentOrder?.taskState,
				offlineMode = 0,
				operateTime = System.currentTimeMillis().toString(),
				lat = it.latitude,
				lng = it.longitude)

			val offlineUpdateTaskBean = OfflineUpdateTaskBean(type = temp.type,
				taskId = temp.taskId,
				flowType = temp.flowType,
				userId = temp.userId,
				vehicleId = temp.vehicleId,
				currentState = temp.currentState,
				offlineMode = 1,
				operateTime = temp.operateTime,
				updateTaskLat = temp.lat,
				updateTaskLng = temp.lng,
				taskCode = uiState.value.orderInfo?.taskCode,
				userOrderId = uiState.value.orderInfo?.userOrderId,
				offlineTitle = "救援车发车，正在赶往现场",
				offlineType = 1)
			insertOfflineTask(offlineUpdateTaskBean)

			updateOrder(getCurrentOrder()?.copy(taskState = getCurrentOrder()?.getNextStatus()))
			updateState(uiState.value.copy(goNextPage = UpdateTaskBean(nextState = getCurrentOrder()?.taskState),
				orderInfo = getCurrentOrder()))
		}, failed = {
			LoadingManager.hideLoading()
			ToastUtils.showShort(it)
		})
	}


	private fun updateTask() {
		LoadingManager.showLoading()
		ZdLocationManager.getSingleLocation(success = {
			LoadingManager.hideLoading()
			val taskRequest = UpdateTaskRequest(type = "ARRIVE_DEST",
				taskId = GlobalData.currentOrder?.taskId,
				userId = GlobalData.driverInfoBean?.userId,
				vehicleId = GlobalData.driverInfoBean?.vehicleId,
				flowType = GlobalData.currentOrder?.flowType,
				currentState = GlobalData.currentOrder?.taskState,
				offlineMode = 0,
				operateTime = System.currentTimeMillis().toString(),
				lat = it.latitude,
				lng = it.longitude)
			doUploadTask(request = taskRequest)
		}, failed = {
			LoadingManager.hideLoading()
			ToastUtils.showShort(it)
		})
	}

	private fun doUploadTask(request : UpdateTaskRequest) {
		if (! getCurrentOrderOfflineTask().isNullOrEmpty()) {
			updateOfflineTask(taskRequest = request)
			return
		}
		LoadingManager.showLoading()
		CommonMethod.updateTask(request, success = {
			LoadingManager.hideLoading()
			updateOrder(getCurrentOrder()?.copy(taskState = it?.nextState))
			updateState(uiState.value.copy(goNextPage = it, orderInfo = getCurrentOrder()))
		}, failed = { msg, code ->
			LoadingManager.hideLoading()
			ToastUtils.showShort(msg)
			if (code == Const.NetWorkException) {
				updateState(uiState.value.copy(showOfflineDialog = true))
			}
			LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg")
		})
	}

	private fun init() {
		updateState(uiState = uiState.value.copy(orderInfo = getCurrentOrder()))
		buildMarkers(getCurrentOrder())
		searchDrivingRoute(getCurrentOrder()) //        dispatch(Action.StartTimer)
	}

	private fun searchDrivingRoute(orderInfo : OrderInfo?) { // 如果没有当前位置，则不进行路径规划
		if (GlobalData.currentLocation == null) return

		val currentPoint = LatLonPoint(GlobalData.currentLocation?.latitude ?: 0.0,
			GlobalData.currentLocation?.longitude ?: 0.0)

		// 获取目的地坐标
		val destPoint =
			if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && orderInfo.distLng != null && orderInfo.distLng != 0.0) {
				LatLonPoint(orderInfo.distLat !!, orderInfo.distLng !!)
			} else null

		// 如果没有目的地，则不进行规划
		if (destPoint == null) return

		// 使用 Application Context 创建路由搜索对象
		val routeSearch = RouteSearch(GlobalData.application)
		routeSearch.setRouteSearchListener(object : RouteSearch.OnRouteSearchListener {
			override fun onDriveRouteSearched(result : DriveRouteResult?, errorCode : Int) {
				if (errorCode == 1000 && result != null && result.paths.isNotEmpty()) {
					val path = result.paths[0]
					val points = path.steps.flatMap { step ->
						step.polyline.map { LatLng(it.latitude, it.longitude) }
					}
					val duration = path.duration
					val arrivalTime = System.currentTimeMillis() + duration * 1000
					val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
					val estimatedTime = dateFormat.format(Date(arrivalTime))
					updateState(uiState.value.copy(routePoints = points,
						estimatedArrivalTime = estimatedTime,
						remainingDistance = path.distance))
				} else {
					LogUtil.print("searchDrivingRoute", "路径规划失败: errorCode=$errorCode")
				}
			}

			override fun onBusRouteSearched(p0 : BusRouteResult?, p1 : Int) {}
			override fun onWalkRouteSearched(p0 : WalkRouteResult?, p1 : Int) {}
			override fun onRideRouteSearched(p0 : RideRouteResult?, p1 : Int) {}
		})

		// 规划当前位置到目的地的路线
		val query = RouteSearch.FromAndTo(currentPoint, destPoint)
		val driveQuery =
			RouteSearch.DriveRouteQuery(query, RouteSearch.DrivingDefault, null, null, "")
		routeSearch.calculateDriveRouteAsyn(driveQuery)
	}

	private fun calculateRemainingDistance() : Pair<Float, String> {
		val currentLocation = GlobalData.currentLocation ?: return Pair(0f, "")
		val orderInfo = _uiState.value.orderInfo ?: return Pair(0f, "")

		// 计算到目的地的距离
		val distance = if (orderInfo.distLat != null && orderInfo.distLng != null) {
			AMapUtils.calculateLineDistance(LatLng(currentLocation.latitude,
				currentLocation.longitude), LatLng(orderInfo.distLat !!, orderInfo.distLng !!))
		} else 0f

		if (distance <= 0f) {
			return Pair(0f, "")
		}

		// 计算预计到达时间（假设平均速度40km/h）
		val timeInSeconds = ((distance / 1000.0 * 60.0 / 40.0) * 60).toInt()
		val calendar = Calendar.getInstance()
		calendar.add(Calendar.SECOND, timeInSeconds)
		val arrivalTime = SimpleDateFormat("HH:mm", Locale.getDefault()).format(calendar.time)

		return Pair(distance, arrivalTime)
	}

	private var timerJob : Job? = null

	private fun startTimer() {
		timerJob?.cancel()
		timerJob = viewModelScope.launch {
			while (isActive) {
				val (distance, arrivalTime) = calculateRemainingDistance()
				_uiState.update {
					it.copy(remainingDistance = distance, estimatedArrivalTime = arrivalTime)
				}
				delay(1000)
			}
		}
	}

	override fun onCleared() {
		super.onCleared()
		timerJob?.cancel()
	}

	private fun buildMarkers(orderInfo : OrderInfo?) {
		val markers = arrayListOf<MarkerOptions>()
		if (orderInfo?.lat != null && orderInfo.lat != 0.0 && orderInfo.lng != null && orderInfo.lng != 0.0) { // 获取矢量图资源文件
			val startMarkers =
				MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map))
					.position(LatLng(orderInfo.lat !!, orderInfo.lng !!)).infoWindowEnable(false)
					.visible(true)
			markers.add(startMarkers)
		}

		if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && orderInfo.distLng != null && orderInfo.distLng != 0.0) {
			val startMarkers =
				MarkerOptions().icon(ImageUtil.vectorToBitmap(ActivityUtils.getTopActivity(), R.drawable.sv_map_dist))
					.position(LatLng(orderInfo.distLat !!, orderInfo.distLng !!)).visible(true)
			markers.add(startMarkers)
		}
		updateState(uiState.value.copy(markers = markers))
	}

	sealed class Action {
		data object Init : Action()
		data object UpdateTask : Action()
		data class UpdateState(val uiState : UiState) : Action()
		data object UploadOffline : Action()
		data object StartTimer : Action()
	}

	data class UiState(val orderInfo : OrderInfo? = null,
		val showCallPhoneDialog : Boolean? = false,
		val markers : ArrayList<MarkerOptions>? = null,
		val goNextPage : UpdateTaskBean? = null,
		val isGoNextPageDialog : Boolean? = null,
		val showOfflineDialog : Boolean? = null,
		val routePoints : List<LatLng>? = null,
		val remainingDistance : Float = 0f,
		val estimatedArrivalTime : String = "")
}