package com.gingersoft.gsa.cloud.service

import android.annotation.SuppressLint
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.gingersoft.gsa.cloud.base.R
import com.gingersoft.gsa.cloud.base.application.GsaCloudApplication
import com.gingersoft.gsa.cloud.base.utils.SoundPoolUtils
import com.gingersoft.gsa.cloud.base.utils.okhttpUtils.OkHttp3Utils
import com.gingersoft.gsa.cloud.base.utils.time.TimeUtils
import com.gingersoft.gsa.cloud.constans.AppConstans
import com.gingersoft.gsa.cloud.constans.HttpsConstans
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 GetInfoUpdateService : Service() {

    private val TAG = "heart"
    /**
     * 心跳检测时间
     */
    private val HEART_BEAT_RATE = (30 * 1000).toLong()//每隔15秒进行一次对长连接的心跳检测
    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 lateinit var mReceiver: ClearHeartBroadcastReceiver

    private var newWakeLock: PowerManager.WakeLock? = null

    private var myBind: MyBind? = null

    private val CHANNEL_ID = "cloud_gsa"

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

    val restaurantId by lazy {
        GsaCloudApplication.getRestaurantId()
    }

    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 {
        Log.d(TAG, "onStartCommand()")
        // 在API11之后构建Notification的方式
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createNotificationChannel()
        } else {
            startNotification()
        }
        putTimeLog("啟動服務onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

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

    @SuppressLint("InflateParams")
    private fun startNotification() {
        val broadcastReceiver = Intent(AppConstans.CLEAR_ORDER_RECEIVING_HEART)
        val broadcastIntent = PendingIntent.getBroadcast(this, 10, broadcastReceiver, 0)
        val remoteViews = RemoteViews(packageName, R.layout.layout_order_receiving)
        remoteViews.setOnClickPendingIntent(R.id.btn_stop_service, broadcastIntent)
        var intent: Intent? = null
        myBind?.jumpActivity?.let {
            intent = Intent(this, it)
        }
        if (intent == null) {
            intent = Intent("action.gingersoft.DELIVERY_ORDER")
        }
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)

        //在创建的通知渠道上发送通知
        val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        builder.setSmallIcon(R.mipmap.ic_launcher) //设置通知图标
                .setContentTitle("Ricepon Pos")//设置通知标题
                .setContentText("外賣接單服務")//设置通知内容Takeaway order service
                .setContent(remoteViews)
                .setContentIntent(pendingIntent)
                .setAutoCancel(false) //用户触摸时，自动关闭
                .setOngoing(true)//设置处于运行状态
                .setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
        //将服务置于启动状态 NOTIFICATION_ID指的是创建的通知的ID
        startForeground(123, builder.build())
    }

    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()
            } else {
                startNotification()
            }
        }

        fun setOnPostCallBack(postCallBack: PostCallBack?) {
            this@GetInfoUpdateService.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@GetInfoUpdateService.isDestroy) {
                            mWebSocket = webSocket
                            val token = "weixin_" + restaurantId + "_" + getRandomString(24)
                            Log.e(TAG, "token：$token")
                            webSocket.send(Gson().toJson(MsgBean(1, token)))
                            putTimeLog("連接成功")
                            cancelTimerDisposable()
                            myBind?.block?.invoke(false)
                            if (postCallBack != null) {
                                postCallBack!!.callBack(0)
                            }
                        }
                    }

                    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)
                        }
                        //-1斷開連接,\n-2:消息傳輸錯誤,\n0:連接消息,\n1：登錄通知,\n2：登出通知,\n3：外賣送單通知,\n4：自取送單通知,\n5:歷史訂單通知,\n6:修改訂單狀態通知,\n7:支付成功通知"
                        if (type == 3 || type == 4 || type == 5
                                || type == 7) {
                            //播放提示音
                            initSoundPool(R.raw.newordervocal)
                        } else if (type == 8) {
                            initSoundPool(R.raw.raw_logistics_cancel)
                        }
                        //收到服务器端传过来的消息text
                        Log.e(TAG, "onMessage：$text")
                        putTimeLog("收到回調：$text")
                    }

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

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

                    override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                        super.onClosed(webSocket, code, reason)
                        Log.e(TAG, "onClosed")
                        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@GetInfoUpdateService.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)
    }

    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()
        putTimeLog("服務銷毀onDestroy")

        //清除心跳
        clearHeart()
        isDestroy = true
        //取消廣播
        unregisterReceiver(mReceiver)
        //斷開長鏈接
        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", 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()
        }
    }

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

    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 token: String)

}