package com.za.ui.new_order

import androidx.lifecycle.viewModelScope
import com.amap.api.maps.model.BitmapDescriptorFactory
import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.MarkerOptions
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.blankj.utilcode.util.ToastUtils
import com.za.base.BaseVm
import com.za.base.view.LoadingManager
import com.za.bean.JpushBean
import com.za.bean.TaskNotesBean
import com.za.bean.request.AcceptOrderRequest
import com.za.bean.request.RefuseOrderRequest
import com.za.bean.request.TaskNotesRequest
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.common.util.DeviceUtil
import com.za.common.util.ImageUtil
import com.za.net.BaseObserver
import com.za.net.RetrofitHelper
import com.za.service.location.ZdLocationManager
import com.za.servicing.R
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
	private val _uiState = MutableStateFlow(UiState())
	val uiState get() = _uiState

	private var timerJob : Job? = null

	override fun dispatch(action : Action) {
		when (action) {
			is Action.Init -> init(action.jpushBean)
			is Action.AcceptOrder -> acceptOrder()
			is Action.RefuseOrder -> refuseOrder()
			is Action.StartTimer -> startTimer()
			is Action.ShowTaskNotes -> showTaskNotes()
			is Action.UpdateTimer -> updateTimer(action.remainingTime)
			else -> {}
		}
	}

	override fun updateState(uiState : UiState) {
		_uiState.value = uiState
	}

	private fun init(jpushBean : JpushBean?) {
		updateState(uiState.value.copy(jpushBean = jpushBean))
		buildMarkers(jpushBean)
		searchDrivingRoute(jpushBean)
		startTimer()
		getTaskNote()
	}

	private fun getTaskNote() {
		val taskNotesRequest = TaskNotesRequest(taskId = uiState.value.jpushBean?.taskId)
		RetrofitHelper.getDefaultService().getTaskNotes(taskNotesRequest)
			.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
			.subscribe(object : BaseObserver<TaskNotesBean>() {
				override fun doSuccess(it : TaskNotesBean?) {
					updateState(uiState.value.copy(taskNotesBean = it))
				}

				override fun doFailure(code : Int, msg : String?) {
					LogUtil.print("获取任务备注失败", "request=$taskNotesRequest msg=$msg")
				}
			})
	}

	private fun buildMarkers(jpushBean : JpushBean?) {
		val markers = arrayListOf<MarkerOptions>()
		if (jpushBean?.lat != null && jpushBean.lat != 0.0 && jpushBean.lng != null && jpushBean.lng != 0.0) {
			val startMarkers =
				MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map))
					.position(LatLng(jpushBean.lat, jpushBean.lng)).title(jpushBean.address)
					.snippet("救援地点").visible(true)
			markers.add(startMarkers)
		}

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

	private fun showTaskNotes() {
		if (uiState.value.taskNotesBean != null && isNeedShowNotes()) {
			updateState(uiState.value.copy(showTaskNotesDialog = true))
			return
		}

		acceptOrder()
	}

	private fun acceptOrder() {
		LoadingManager.showLoading()
		ZdLocationManager.getSingleLocation(success = {
			val orderInfo = uiState.value.jpushBean
			val acceptOrderRequest = AcceptOrderRequest()
			acceptOrderRequest.taskId = orderInfo?.taskId
			acceptOrderRequest.vehicleId = GlobalData.driverInfoBean?.vehicleId
			acceptOrderRequest.userId = GlobalData.driverInfoBean?.userId
			acceptOrderRequest.taskCode = orderInfo?.taskCode
			acceptOrderRequest.deviceId = DeviceUtil.getAndroidId(ActivityUtils.getTopActivity())
			acceptOrderRequest.lat = it.latitude
			acceptOrderRequest.lng = it.longitude
			RetrofitHelper.getDefaultService().acceptOrder(acceptOrderRequest)
				.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
				.subscribe(object : BaseObserver<String>() {
					override fun doSuccess(it : String?) {
						LoadingManager.hideLoading()
						LogUtil.print("接单成功", "request=$acceptOrderRequest")
						updateState(uiState.value.copy(showCallPhoneDialog = orderInfo?.isNeedCallCustomPhone()))
					}

					override fun doFailure(code : Int, msg : String?) {
						LoadingManager.hideLoading()
						LogUtil.print("接单失败", "request=$acceptOrderRequest msg=$msg")
					}
				})
		}, failed = {
			LoadingManager.hideLoading()
			LogUtil.print("接单时获取定位失败", it)
		})
	}

	private fun refuseOrder() {
		LoadingManager.showLoading()
		RetrofitHelper.getDefaultService()
			.refuseOrder(RefuseOrderRequest(taskId = uiState.value.jpushBean?.taskId,
				vehicleId = GlobalData.driverInfoBean?.vehicleId,
				taskCode = uiState.value.jpushBean?.taskCode,
				userId = GlobalData.driverInfoBean?.userId)).subscribeOn(Schedulers.io())
			.observeOn(AndroidSchedulers.mainThread()).subscribe(object : BaseObserver<String>() {
				override fun doSuccess(it : String?) {
					LoadingManager.hideLoading()
					updateState(uiState.value.copy(refuseSuccess = true))
					LogUtil.print("refuseOrder", "订单拒绝成功")
				}

				override fun doFailure(code : Int, msg : String?) {
					LoadingManager.hideLoading()
					ToastUtils.showShort(msg)
					LogUtil.print("refuseOrder", "failed=$msg")
				}
			})
	}

	private fun startTimer() {
		timerJob?.cancel()
		timerJob = viewModelScope.launch {
			try {
				var timeLeft = 120
				while (timeLeft > 0 && isActive) {
					delay(1000)
					timeLeft --
					updateState(uiState.value.copy(remainingTime = timeLeft))
				}
				if (timeLeft == 0 && isActive) { // 倒计时结束,显示订单超时
					updateState(uiState.value.copy(isTimeout = true, showTimeoutDialog = true))
				}
			} catch (e : Exception) {
				LogUtil.print("startTimer", "倒计时异常: ${e.message}")
			}
		}
	}

	private fun isNeedShowNotes() : Boolean {
		if (! uiState.value.taskNotesBean?.taskNotes.isNullOrBlank()) {
			return true
		}

		if (! uiState.value.taskNotesBean?.customerNotes.isNullOrBlank()) {
			return true
		}

		if (! uiState.value.taskNotesBean?.feeStandard.isNullOrBlank()) {
			return true
		}

		if (! uiState.value.taskNotesBean?.otherNotes.isNullOrBlank()) {
			return true
		}

		return false
	}

	private fun updateTimer(remainingTime : Int) {
		updateState(uiState.value.copy(remainingTime = remainingTime))
	}

	private fun searchDrivingRoute(jpushBean : JpushBean?) {
		if (GlobalData.currentLocation == null) {
			ToastUtils.showShort("获取当前位置失败")
			return
		}

		updateState(uiState.value.copy(isLoading = true))

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

		val endPoint = when {
			jpushBean?.distLat != null && jpushBean.distLat != 0.0 && jpushBean.distLng != null && jpushBean.distLng != 0.0 -> {
				LatLonPoint(jpushBean.distLat, jpushBean.distLng)
			}

			jpushBean?.lat != null && jpushBean.lat != 0.0 && jpushBean.lng != null && jpushBean.lng != 0.0 -> {
				LatLonPoint(jpushBean.lat, jpushBean.lng)
			}

			else -> null
		}

		if (endPoint == null) return

		val fromAndTo = RouteSearch.FromAndTo(startPoint, endPoint)
		val query =
			RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DrivingDefault, null, null, "")

		RouteSearch(GlobalData.application).apply {
			setRouteSearchListener(object : RouteSearch.OnRouteSearchListener {
				override fun onDriveRouteSearched(result : DriveRouteResult?, errorCode : Int) {
					updateState(uiState.value.copy(isLoading = false))

					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,
							remainingDistance = path.distance.toDouble(),
							estimatedArrivalTime = estimatedTime))
					} else {
						ToastUtils.showShort("路线规划失败，请重试")
						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) {}
			})
			calculateDriveRouteAsyn(query)
		}
	}

	override fun onCleared() {
		super.onCleared()
		try {
			timerJob?.cancel()
			timerJob = null
		} catch (e : Exception) {
			LogUtil.print("onCleared", "取消倒计时异常: ${e.message}")
		}
	}

	sealed class Action {
		data class Init(val jpushBean : JpushBean?) : Action()
		data object AcceptOrder : Action()
		data class UpdateState(val uiState : UiState) : Action()
		data object RefuseOrder : Action()
		data object ShowTaskNotes : Action()
		data object StartTimer : Action()
		data class UpdateTimer(val remainingTime : Int) : Action()
	}

	data class UiState(val jpushBean : JpushBean? = null,
		val showCallPhoneDialog : Boolean? = false,
		val markers : ArrayList<MarkerOptions>? = null,
		val refuseSuccess : Boolean? = false,
		val taskNotesBean : TaskNotesBean? = null,
		val showTaskNotesDialog : Boolean? = false,
		val acceptOrderDialog : Boolean? = null,
		val remainingTime : Int = 50,
		val routePoints : List<LatLng>? = null,
		val remainingDistance : Double = 0.0,
		val estimatedArrivalTime : String = "",
		val isLoading : Boolean = false,
		val isTimeout : Boolean = false,
		val showTimeoutDialog : Boolean = false)


}