package com.dafay.demo.aidl.service

import android.app.Service
import android.content.Intent
import android.os.DeadObjectException
import android.os.IBinder
import com.dafay.demo.aidl.TestInterface
import com.dafay.demo.aidl.callback.MethodCallback
import com.dafay.demo.aidl.callback.ReceiveMessageCallback
import com.dafay.demo.aidl.callback.ServiceConnectCallback
import com.dafay.demo.lib.base.utils.debug
import com.dafay.demo.lib.base.utils.error
import java.util.Random
import java.util.Timer
import java.util.TimerTask

class TestService : Service() {
    private var count = 0
    private var autoIncreaseNum = 0
    private val receiveMessageCallbacks: HashMap<Int, ReceiveMessageCallback> = HashMap()
    private val deathRecipientMap: HashMap<Int, ClientDeathRecipient> = HashMap()

    override fun onCreate() {
        super.onCreate()
        initTimer()
    }

    private fun initTimer() {
        Timer().schedule(object : TimerTask() {
            override fun run() {
                autoIncreaseNum += 10
                dealDispatchMsg("count:${count} autoIncreaseNum:${autoIncreaseNum}")
            }
        }, 0, 5000)
    }

    /**
     * 处理 DeadObjectException 问题，当遍历到已死亡 client 的引用，从列表中删除
     * 虽然在 ClientDeathRecipient 已经做了监听删除（遍历先于删除发生，依然会有问题），更安全的方式，在遍历过程中再处理一次
     */
    private fun dealDispatchMsg(msg: String?) {
        val iterator: Iterator<Int> = receiveMessageCallbacks.keys.toList().iterator()
        while (iterator.hasNext()) {
            val key = iterator.next()
            val receiveMessageCallback = receiveMessageCallbacks[key]
            try {
                receiveMessageCallback?.onReceive(msg)
            } catch (e: Exception) {
                if (e is DeadObjectException) {
                    receiveMessageCallbacks.remove(key)
                }
                error(e.message ?: "")
            }
        }
    }

    override fun onBind(intent: Intent): IBinder {
        return TestStub()
    }

    /**
     * 没有客户端与其绑定时，便会销毁
     */
    override fun onDestroy() {
        super.onDestroy()
        debug("onDestroy()")
    }

    inner class TestStub : TestInterface.Stub() {
        /**
         * methodCallback 依然有可能发生 DeadObjectException 异常，对此做 try catch 处理
         */
        override fun add(value: Int, methodCallback: MethodCallback?) {
            // 模拟耗时操作
            Thread.sleep(500 + Random().nextInt(1500).toLong())
            try {
                if (System.currentTimeMillis() % 2 == 0L) {
                    count += value
                    methodCallback?.onSuccess(count.toString())
                } else {
                    methodCallback?.onFailure("add exec fail")
                }
            } catch (e: Exception) {
                error(e.message ?: "")
            }
        }

        override fun send(msg: String?): Int {
            debug("msg.length:${msg?.length}")
            return 0
        }

        override fun registerReceiveMessageCallback(callback: ReceiveMessageCallback?): Int {
            callback ?: return -1
            receiveMessageCallbacks[getCallingPid()] = callback
            return 0
        }

        override fun unregisterReceiveMessageCallback(callback: ReceiveMessageCallback?): Int {
            callback ?: return -1
            receiveMessageCallbacks.remove(getCallingPid())
            return 0
        }

        override fun registerServiceCallback(callback: ServiceConnectCallback?) {
            callback ?: return
            val deathRecipient = ClientDeathRecipient(getCallingPid(), callback)
            deathRecipientMap[getCallingPid()] = deathRecipient
            callback.asBinder().linkToDeath(deathRecipient, 0)
        }

        override fun unregisterServiceCallback(callback: ServiceConnectCallback?) {
            if (deathRecipientMap.containsKey(getCallingPid())) {
                val deathRecipient: ClientDeathRecipient? = deathRecipientMap.remove(getCallingPid())
                deathRecipient?.callBack?.asBinder()?.unlinkToDeath(deathRecipient, 0)
            }
        }
    }

    inner class ClientDeathRecipient(private val pid: Int, val callBack: ServiceConnectCallback) :
        IBinder.DeathRecipient {
        override fun binderDied() {
            debug("receive client death recipient")
            deathRecipientMap.remove(pid)
            // 移除对应死亡客户端的回调，否则会触发 DeadObjectException
            receiveMessageCallbacks.remove(pid)
        }
    }
}