package com.mogo.v2x

import android.os.Handler
import android.os.Looper
//import com.mogo.cloud.location.LocationManager
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.cloud.socket.SocketManager
import com.mogo.v2x.callback.IV2XCallback
import com.mogo.v2x.config.V2XConfig
import com.mogo.v2x.data.V2XMarkerResponse
import com.mogo.v2x.event.V2XEvent
import com.mogo.v2x.http.V2XRefreshModel
import com.mogo.v2x.http.callback.IV2XRefreshCallback
import com.mogo.v2x.logger.Logger
import com.mogo.v2x.socket.*
import com.mogo.v2x.socket.V2XMessageListener_401012
import com.mogo.v2x.socket.V2XMessageListener_401018
import com.mogo.v2x.socket.V2XMessageListener_402000
import com.mogo.v2x.socket.V2XMessageListener_404000
import com.mogo.v2x.socket.V2XMessageListener_503000
import com.mogo.v2x.utils.DistanceUtils
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference

object V2XManager {

    internal const val TAG = "V2XManager"

    private val config: AtomicReference<V2XConfig> by lazy {
        AtomicReference<V2XConfig>(null)
    }

    private val cbs by lazy {
        CopyOnWriteArrayList<IV2XCallback>()
    }

    private val lastLongitude by lazy {
        AtomicReference(0.0)
    }

    private val lastLatitude by lazy {
        AtomicReference(0.0)
    }

    private val realLongitude by lazy { AtomicReference(0.0) }

    private val realLatitude by lazy { AtomicReference(0.0) }



    /**
     * 标识此参数是否启动
     */
    private val started by lazy {
        AtomicBoolean(false)
    }

    private val refreshCallback = object : IV2XRefreshCallback<V2XMarkerResponse> {

        override fun onSuccess(result: V2XMarkerResponse) {
            cbs.forEach {
                it.onAck(V2XEvent.Marker(result))
            }
        }

        override fun onFail(msg: String?) {
            cbs.forEach {
                it.onFail(msg ?: "")
            }
        }
    }


    private val refreshTask = object : Runnable {
        override fun run() {
            V2XRefreshModel.querySnapshot(longitude = this@V2XManager.realLongitude.get(), latitude = this@V2XManager.realLatitude.get(), refreshCallback)
            handler.postDelayed(this, config.get().durationForTriggerRefresh)
        }
    }

    private val handler by lazy {
        Handler(Looper.getMainLooper())
    }

    /**
     * 根据所配置的参数，初始化V2X相关功能（注: 此方法不要重复调用，非首次调用会抛异常）
     * @param config 相关配置类
     */
    fun init(config: V2XConfig) {
        Logger.d(TAG, "-- init --")
        if (this.config.get() != null) {
            throw IllegalStateException("V2XManager has been initialized, don't initialize repeatably.")
        }
        this.config.set(config)
        Logger.loggable = config.loggable
    }

    /**
     * - 开启V2X功能, 此方法调用前，要确保满足以下两个条件：
     *  1.初始化方法[init]已调用
     *  2.确保[MoGoAiCloudClientConfig.sn]和[MoGoAiCloudClientConfig.token]两个值存在，如果其中有一个值不存在，不会启动相关功能
     * - 此函数的功能如下：
     *  1.建立长链接[SocketManager.init]
     *  2.位置上报服务[LocationManager.init]和[LocationManager.start]
     *  3.短链[V2XRefreshModel.querySnapshot]定时轮循,轮循时长取[V2XConfig.durationForTriggerRefresh]
     */
    fun start() {
        Logger.d(TAG, "-- start --")
        val config = config.get() ?: throw IllegalStateException("V2XManager has not been initialized, please invoke V2XManager#init(config: X2XConfig) firstly.")
        if (started.get()) {
            Logger.d(TAG, "-- has been started --")
            return
        }
        if (config.aiCloudConfig.sn?.isBlank() == true) {
            Logger.e(TAG, "sn is null or blank, please ensure sn exists and then invoke V2XManager#start() again.")
            cbs.forEach {
                it.onFail("sn is null or blank, please ensure sn exists and then invoke V2XManager#start() again.")
            }
            return
        }
        if (config.aiCloudConfig.token?.isBlank() == true) {
            Logger.e(TAG, "token is null or blank, please ensure token exists and then invoke V2Manager#start() again.")
            cbs.forEach {
                it.onFail("token is null or blank, please ensure token exists and then invoke V2Manager#start() again.")
            }
            return
        }
        if (started.compareAndSet(false, true)) {
            Logger.d(TAG, "-- start real --")
            SocketManager.getInstance().init(config.context,"",0.0,0.0)
            SocketManager.getInstance().registerOnMessageListener(401012, V2XMessageListener_401012(cbs))
            SocketManager.getInstance().registerOnMessageListener(401018, V2XMessageListener_401018(cbs))
            SocketManager.getInstance().registerOnMessageListener(402000, V2XMessageListener_402000(cbs))
            SocketManager.getInstance().registerOnMessageListener(404000, V2XMessageListener_404000(cbs))
            SocketManager.getInstance().registerOnMessageListener(503000, V2XMessageListener_503000(cbs))

//            LocationManager.getInstance().init(config.context)
//            LocationManager.getInstance().start()
            handler.post(refreshTask)
        }
    }

    /**
     * @param sn 更新后的sn
     * @param token 更新后的token
     */
    fun updateSnAndToken(sn: String?, token: String?) {
        val config = config.get() ?: throw IllegalStateException("V2XManager has not been initialized, please invoke V2XManager#init(config: X2XConfig) firstly.")
        sn ?: return
        token ?: return
        if (started.get()) {
            return
        }
        config.aiCloudConfig.sn = sn
        config.aiCloudConfig.token = token
        start()
    }

    /**
     * 停止V2X功能
     * 1. 断开长链接[SocketManager.release]
     * 2. 停止位置上报[LocationManager.stop]
     * 3. 取消短链定时轮循任务
     */
    fun stop() {
        Logger.d(TAG, "-- stop --")
        if (config.get() == null) {
            throw IllegalStateException("V2XManager has not been initialized, please invoke V2XManager#init(config: X2XConfig) firstly.")
        }
        if (started.compareAndSet(true, false)) {
            Logger.d(TAG, "-- stop real --")
            SocketManager.getInstance().release()
//            LocationManager.getInstance().stop()
            handler.removeCallbacks(refreshTask)
            lastLatitude.set(0.0)
            lastLongitude.set(0.0)
        }
    }

    /**
     * 添加相关信息接口回调
     * @param cb 要添加的回调接口
     */
    fun addCallback(cb: IV2XCallback) {
        Logger.d(TAG, "-- addCallback --")
        if (cbs.contains(cb)) {
            return
        }
        cbs += cb
    }

    /**
     * 移除相关信息接口回调
     * @param cb 要移除的回调接口
     */
    fun removeCallback(cb: IV2XCallback) {
        Logger.d(TAG, "-- removeCallback --")
        if (!cbs.contains(cb)) {
            return
        }
        cbs.remove(cb)
    }

    /**
     * 当自车位置变量时调用
     * @param longitude 自车所在精度
     * @param latitude  自车所在纬度
     */
    fun onLocationChanged(longitude: Double, latitude: Double) {
        if (config.get() == null) {
            throw IllegalStateException("V2XManager has not been initialized, please invoke V2XManager#init(config: X2XConfig) firstly.")
        }
        if (!started.get()) {
            return
        }
        Logger.d(TAG, "--- onLocationChanged --[longitude: $longitude, latitude: $latitude]")
        realLongitude.set(longitude)
        realLatitude.set(latitude)
        val oldLon = this.lastLongitude.get()
        val oldLat = this.lastLatitude.get()
        var update = false
        try {
            if (oldLon == 0.0 || oldLat == 0.0) {
                Logger.d(TAG, "--- onLocationChanged -- first --[longitude: $longitude, latitude: $latitude]")
                handler.removeCallbacks(refreshTask)
                handler.post(refreshTask)
                update = true
                return
            }
            if (DistanceUtils.calculateLineDistance(oldLon, oldLat, longitude, latitude) >= this.config.get().distanceForTriggerRefresh) {
                Logger.d(TAG, "--- onLocationChanged -- trigger --[longitude: $longitude, latitude: $latitude]")
                handler.removeCallbacks(refreshTask)
                handler.post(refreshTask)
                update = true
            }
        } finally {
            if (update) {
                this.lastLatitude.set(latitude)
                this.lastLongitude.set(longitude)
            }
        }
    }

    /**
     * 是否已经初始化
     * @return true: 已初始化过 false: 未初始化
     */
    fun hasInit() = this.getConfig() != null

    /**
     * 强制刷新道路事件
     */
    fun forceRefresh() {
        if (hasInit()) {
            handler.removeCallbacks(refreshTask)
            handler.post(refreshTask)
        }
    }

    internal fun getConfig() = this.config.get()
}