package com.gingersoft.gsa.cloud.common.service

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.BitmapFactory
import android.os.Binder
import android.os.Build
import android.os.IBinder
import android.os.PowerManager
import android.util.Log
import android.widget.RemoteViews
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import com.billy.cc.core.component.CC
import com.gingersoft.gsa.cloud.common.R
import com.gingersoft.gsa.cloud.common.constans.AppConstans
import com.gingersoft.gsa.cloud.common.constans.HttpsConstans
import com.gingersoft.gsa.cloud.common.core.restaurant.RestaurantInfoManager
import com.gingersoft.gsa.cloud.common.core.user.UserContext
import com.gingersoft.gsa.cloud.common.logan.LoganManager
import com.gingersoft.gsa.cloud.common.utils.SoundPoolUtils
import com.gingersoft.gsa.cloud.common.utils.okhttpUtils.OkHttp3Utils
import com.gingersoft.gsa.cloud.common.utils.time.TimeUtils
import com.gingersoft.gsa.cloud.component.ComponentName
import com.google.gson.Gson
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.*
import okio.ByteString
import org.json.JSONObject
import java.util.*
import java.util.concurrent.TimeUnit

class DataNotificationService : Service() {

    private val TAG = "heart"

    /**
     * 心跳检测时间
     */
    private val HEART_BEAT_RATE = (30 * 1000).toLong()//每隔30秒进行一次对长连接的心跳检测
    private val WEBSOCKET_HOST_AND_PORT = "${HttpsConstans.ROOT_URL}/ricepon-websocket/js/webSocketServer"//可替换为自己的主机名和端口号

    private var mWebSocket: WebSocket? = null
    var client: OkHttpClient? = null

    var postCallBack: PostCallBack? = null
    private var mReceiver: ClearHeartBroadcastReceiver? = null

    private var newWakeLock: PowerManager.WakeLock? = null

    private var myBind: MyBind? = null

    private val CHANNEL_ID = "cloud_gsa"

    private var isCreate = false


    /**
     * prj數據
     */
    private var PRJ_DATA = 10

    /**
     * prj數據
     */
    private var TABLE_DATA = 11

    private var NOMAL_NOTIFITY_ID = 456
    private var DELIVETY_NOTIFITY_ID = 123

    companion object {
        @kotlin.jvm.JvmField
        var loginfo = StringBuffer()


        @kotlin.jvm.JvmField
        var CONNECTION_TYPE = "connection_type"

        /**
         * 开启外送接单长连
         */
        @kotlin.jvm.JvmField
        var OPEN_DELIVET_ORDER_CONNECTION = 2

        /**
         * 开启数据接收长连（prj,餐台数据）
         */
        @kotlin.jvm.JvmField
        var OPEN_OTHER_CONNECTION = 1

        /**
         * 当前连接类型
         */
        @kotlin.jvm.JvmField
        var mCurrConnectionType = OPEN_OTHER_CONNECTION


    }

    override fun onBind(intent: Intent?): IBinder? {
        myBind = MyBind()
        return myBind
    }


    override fun onCreate() {
        super.onCreate()
        val mFilter = IntentFilter(AppConstans.CLEAR_ORDER_RECEIVING_HEART)
        mReceiver = ClearHeartBroadcastReceiver()
        registerReceiver(mReceiver, mFilter)

        InitSocketThread().start()
        isDestroy = false
        putTimeLog("創建服務onCreate")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        //获取当前长连类型
        intent?.let {
            mCurrConnectionType = it.getIntExtra(CONNECTION_TYPE, OPEN_DELIVET_ORDER_CONNECTION)
        }

        initNotification()

        if (isCreate) {
            send(mCurrConnectionType)
        }
        isCreate = true

        putTimeLog("啟動服務onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    private fun initNotification() {
        if (mCurrConnectionType == OPEN_DELIVET_ORDER_CONNECTION) {
            // 在API11之后构建Notification的方式
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                createNotificationChannel(DELIVETY_NOTIFITY_ID)
            } else {
                startNotification(DELIVETY_NOTIFITY_ID)
            }
        } else {
            // 在API11之后构建Notification的方式
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                createNotificationChannel(NOMAL_NOTIFITY_ID)
            } else {
                startNotification(NOMAL_NOTIFITY_ID)
            }
        }
    }

    /**
     * 创建通知渠道
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun createNotificationChannel(notifyId: Int) {
        //设定的通知渠道名称
        val channelName = "Data Notification"
        //设置通知的重要程度
        val importance = NotificationManager.IMPORTANCE_LOW
        //构建通知渠道
        val channel = NotificationChannel(CHANNEL_ID, channelName, importance)
        channel.description = "Data Notification"
        //向系统注册通知渠道，注册后不能改变重要性以及其他通知行为
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
        notificationManager.cancelAll()
        startNotification(notifyId)
    }

    private fun startNotification(notifiyId: Int) {
        val broadcastReceiver = Intent(AppConstans.CLEAR_ORDER_RECEIVING_HEART)
        val broadcastIntent = PendingIntent.getBroadcast(this, 10, broadcastReceiver, 0)

        var remoteViews: RemoteViews

        if (notifiyId == DELIVETY_NOTIFITY_ID) {
            remoteViews = RemoteViews(packageName, R.layout.notifity_remote_order_receiving)
            remoteViews.setOnClickPendingIntent(R.id.btn_stop_service, broadcastIntent)
        } else {
            remoteViews = RemoteViews(packageName, R.layout.notifity_remote_receive_command)
        }

        //在创建的通知渠道上发送通知
        val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        builder.setSmallIcon(R.mipmap.ic_launcher) //设置通知图标
        builder.setContentTitle("Ricepon POS")//设置通知标题
        builder.setContentText("connection service")//设置通知内容

        val pendingIntent: PendingIntent
        if (notifiyId == DELIVETY_NOTIFITY_ID) {
            var intent: Intent? = null
            myBind?.jumpActivity?.let {
                intent = Intent(this, it)
            }
            if (intent == null) {
                intent = Intent("action.gingersoft.DELIVERY_ORDER")
            }
            pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
            builder.setContentIntent(pendingIntent)
        }
        builder.setContent(remoteViews)
        builder.setAutoCancel(false) //用户触摸时，自动关闭
        builder.setOngoing(true)//设置处于运行状态
        builder.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
        //将服务置于启动状态 NOTIFICATION_ID指的是创建的通知的ID
        startForeground(notifiyId, builder.build())
        if (!UserContext.newInstance().isLogin) {
            stopSelf()
            return
        }
    }

    fun restartNotification() {
        mCurrConnectionType = OPEN_OTHER_CONNECTION;
        //先停止前台服務
        stopForeground(true)
        // 在API11之后构建Notification的方式
        initNotification()
    }

    inner class MyBind : Binder() {
        lateinit var block: (isShow: Boolean) -> Unit
        var jumpActivity: Class<*>? = null
            set(value) {
                field = value
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    createNotificationChannel(DELIVETY_NOTIFITY_ID)
                } else {
                    startNotification(DELIVETY_NOTIFITY_ID)
                }
            }

        fun setOnPostCallBack(postCallBack: PostCallBack?) {
            this@DataNotificationService.postCallBack = postCallBack
        }

        fun execute(block: (isShow: Boolean) -> Unit) {
            this.block = block
        }
    }

    internal inner class InitSocketThread : Thread() {
        override fun run() {
            super.run()
            initSocket()
        }
    }

    // 初始化socket
    private fun initSocket() {
        putTimeLog("取消心跳")
        cancelInterval()
        interval({
            //保持設備喚醒
            newWakeLock?.acquire(10 * 60 * 1000L /*10 minutes*/)
            putTimeLog("開啟心跳")
            //先斷開之前的
            client?.let { it ->
                mWebSocket?.let {
                    it.cancel()
                    it.send("-1")
                    it.close(1000, null)
                }
                it.dispatcher().cancelAll()
            }
            client = OkHttpClient.Builder().readTimeout(9 * 10, TimeUnit.SECONDS).build()
            client?.let {
                val request = Request.Builder()
                        .url(WEBSOCKET_HOST_AND_PORT)
                        .build()
                it.newWebSocket(request, object : WebSocketListener() {
                    override fun onOpen(webSocket: WebSocket, response: Response) {//开启长连接成功的回调
                        super.onOpen(webSocket, response)
                        if (!this@DataNotificationService.isDestroy) {
                            mWebSocket = webSocket
                            send(mCurrConnectionType)
                            putTimeLog("連接成功")
                            cancelTimerDisposable()
                            myBind?.block?.invoke(false)
                        }
                    }

                    override fun onMessage(webSocket: WebSocket, text: String) {//接收消息的回调
                        super.onMessage(webSocket, text)
                        val json = JSONObject(text)
                        val type = json.optInt("type")
                        if (postCallBack != null) {
                            postCallBack!!.callBack(type)
                        }
                        //收到服务器端传过来的消息text
                        putTimeLog("收到回調：$text")
                        //-1斷開連接,
                        // \n-2:消息傳輸錯誤,
                        // \n0:連接消息,
                        // \n1：登錄通知,
                        // \n2：登出通知,
                        // \n3：外賣送單通知,
                        // \n4：自取送單通知,
                        // \n5:歷史訂單通知,
                        // \n6:修改訂單狀態通知,
                        // \n7:支付成功通知"
                        // 10:prj数据
                        // 11:餐台数据
                        if (type == 3 || type == 4 || type == 5 || type == 7) {
                            //播放提示音
                            initSoundPool(R.raw.newordervocal)
                        } else if (type == 8) {
                            initSoundPool(R.raw.raw_logistics_cancel)
                        } else if (type == PRJ_DATA) {
                            CC.obtainBuilder(ComponentName.COMPONENT_PRINT)
                                    .setActionName("getPrjData")
                                    .build()
                                    .call()
                        } else if (type == TABLE_DATA) {

                        }
                    }

                    override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                        super.onMessage(webSocket, bytes)
                        val json = JSONObject(bytes.toString())
                        putTimeLog("onMessage2：$bytes")
                        if (postCallBack != null) {
                            postCallBack!!.callBack(json.optInt("type"))
                        }
                    }

                    override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
                        super.onClosing(webSocket, code, reason)
                        //連接斷開，
                        putTimeLog("onClosing關閉連接")
                    }

                    override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                        super.onClosed(webSocket, code, reason)
                        putTimeLog("onClosed斷開連接")
                        webSocket.cancel()
                    }

                    override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {//长连接连接失败的回调
                        super.onFailure(webSocket, t, response)
                        Log.e(TAG, "onFailure " + t.message)
                        if (!this@DataNotificationService.isDestroy) {
                            //連接斷開，定時五秒，如果未重連，播放提示音
                            delayFun({
                                initSoundPool(R.raw.raw_disconnect)
                                myBind?.block?.invoke(true)
                                //推送給相關人員
                                OkHttp3Utils.noticePersonnel(AppConstans.RP_HEART_ERROR, "心跳斷開十秒以上未連接成功：" + t.message)
                            }, 10)
                            putTimeLog("onFailure連接失敗，等待一分鐘後重新連接")
                        } else {
                            webSocket.cancel()
                            it.dispatcher().cancelAll()
                        }

                    }
                })
                it.dispatcher().executorService().shutdown()
            }
        }, HEART_BEAT_RATE)
    }

    fun send(currConnectionType: Int) {
//        val token = "weixin_" + RestaurantInfoManager.newInstance().restaurantId + "_" + UserContext.newInstance().memberId + "_" + getRandomString(24)
        val token = "weixin_" + RestaurantInfoManager.newInstance().restaurantId + "_" + getRandomString(24)
        LoganManager.w_code(TAG, "token=" + token);
        if (mWebSocket != null) {
            mWebSocket?.send(Gson().toJson(MsgBean(1, getConnectiontype(), token)))
        }
    }

    private fun getConnectiontype(): String {
        var connectiontype = "$OPEN_OTHER_CONNECTION"
        if (mCurrConnectionType == OPEN_DELIVET_ORDER_CONNECTION) {
            connectiontype = "$OPEN_OTHER_CONNECTION , $OPEN_DELIVET_ORDER_CONNECTION"
        }
        return connectiontype
    }

    private var lastSoundTime: Long = 0L
    fun initSoundPool(resId: Int) {
        val nowTime = System.currentTimeMillis()//當前時間減去上次播放的時間，如果超過五秒，那麼才會再次播放提示聲
        if (nowTime - lastSoundTime > 5000) {
            putTimeLog("現在時間：$nowTime 上次播放時間：$lastSoundTime")
            putTimeLog("新訂單播放：$nowTime")
            lastSoundTime = nowTime
            SoundPoolUtils.initSoundPool(this, resId)
        }
    }

    /*获取一条随机字符串*/
    fun getRandomString(length: Int): String { //length表示生成字符串的长度
        val base = "abcdefghijklmnopqrstuvwxyz0123456789"
        val random = Random()
        val sb = StringBuffer()
        for (i in 0 until length) {
            val number = random.nextInt(base.length)
            sb.append(base[number])
        }
        return sb.toString()
    }

    private var isDestroy = false

    override fun onDestroy() {
        super.onDestroy()
        clearTask()
    }

    private fun clearTask() {
        putTimeLog("服務銷毀onDestroy")
        //清除心跳
        clearHeart()
        isDestroy = true
        //取消廣播
        mReceiver?.let {
            unregisterReceiver(mReceiver)
            mReceiver = null
        }
        //斷開長鏈接
        client?.let {
            mWebSocket?.cancel()
            it.dispatcher().cancelAll()
        }
        if (mWebSocket != null) {
            mWebSocket!!.send("-1")
            mWebSocket!!.close(1000, null)
        }
        //停止定時心跳
        cancelInterval()
        //停止延遲執行任務
        cancelTimerDisposable()
        //停止前台服務
        stopForeground(true)
        //清除保持喚醒
        newWakeLock?.release()
        newWakeLock = null
    }

    private fun clearHeart() {
        val requestBody = FormBody.Builder()
                .add("restaurantId", RestaurantInfoManager.newInstance().restaurantId.toString())
                .build()
        OkHttp3Utils.post(HttpsConstans.ROOT_URL + "/member-web/api/restaurant/clearHeartbeat", requestBody)
                .subscribeOn(Schedulers.io()).subscribe()
    }

    inner class ClearHeartBroadcastReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            //關閉service，會調用service的onDestroy
//            stopSelf()
            restartNotification()
            send(mCurrConnectionType)
        }
    }

    /**
     * 向日誌添加數據
     */
    private fun putTimeLog(content: String) {
        loginfo.append(TimeUtils.getCurrentDate(TimeUtils.DEFAULT_DATE_FORMAT))
        loginfo.append("：")
        loginfo.append(content)
        loginfo.append("\n")
        LoganManager.w_network(TAG + " -> " + content);
    }

    var mIntervalDisposable: Disposable? = null
    var timerDisposable: Disposable? = null

    /**
     * 执行定时任务
     */
    fun interval(block: () -> Unit, milliseconds: Long) {
        Observable.interval(0, milliseconds, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Observer<Long> {
                    override fun onError(e: Throwable) {}
                    override fun onComplete() {}
                    override fun onNext(t: Long) {
                        block()
                    }

                    override fun onSubscribe(d: Disposable) {
                        mIntervalDisposable = d
                    }
                })
    }

    /**
     * 取消定时器
     */
    fun cancelInterval() {
        if (mIntervalDisposable != null && !mIntervalDisposable!!.isDisposed) {
            mIntervalDisposable!!.dispose()
        }
    }

    fun cancelTimerDisposable() {
        if (timerDisposable != null && !timerDisposable!!.isDisposed) {
            timerDisposable!!.dispose()
        }
    }

    fun delayFun(block: () -> Unit, milliseconds: Long) {
        Observable.timer(milliseconds, TimeUnit.SECONDS)
                .subscribe(object : Observer<Long> {
                    override fun onSubscribe(d: Disposable) {
                        timerDisposable = d
                    }

                    override fun onNext(t: Long) {
                        block()
                    }

                    override fun onError(e: Throwable) {
                    }

                    override fun onComplete() {

                    }
                })
    }

    class MsgBean(var type: Int, var data: String, var token: String)

}