package com.dafay.demo.aidl.proxy

import android.app.Application
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.os.RemoteException
import com.dafay.demo.aidl.TestInterface
import com.dafay.demo.aidl.callback.ReceiveMessageCallback
import com.dafay.demo.aidl.callback.ServiceConnectCallback
import com.dafay.demo.aidl.inter.ReceiveListener
import com.dafay.demo.lib.base.utils.ApplicationUtils
import com.dafay.demo.lib.base.utils.debug
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

private const val SERVICE_PKG_NAME = "com.dafay.demo.aidl.server"
private const val SERVICE_CLASS_NAME = "com.dafay.demo.aidl.service.TestService"

/**
 * 使用协程，包装服务先连接，再执行远程方法
 */
abstract class BaseServiceConnect {
    private var application: Application = ApplicationUtils.getApp()
    private var intent: Intent = Intent().apply { component = ComponentName(SERVICE_PKG_NAME, SERVICE_CLASS_NAME) }

    protected var remoteServiceProxy: TestInterface? = null
    protected var receiveListeners = CopyOnWriteArrayList<ReceiveListener>()
    protected val mainHandler = Handler(Looper.getMainLooper())
    private val receiveMessageCallback: ReceiveMessageCallback = object : ReceiveMessageCallback.Stub() {
        @Throws(RemoteException::class)
        override fun onReceive(payload: String) {
            debug("onReceive:$payload")
            mainHandler.post {
                receiveListeners.forEach { it.onReceive(payload) }
            }
        }
    }
    private val serviceConnectCallback: ServiceConnectCallback = object : ServiceConnectCallback.Stub() {
        @Throws(RemoteException::class)
        override fun onConnectReply(message: String) {
        }
    }

    private fun bindToService(callback: ((Boolean) -> Unit)) {
        if (remoteServiceProxy != null && remoteServiceProxy!!.asBinder().isBinderAlive) {
            callback.invoke(true)
            return
        }
        val serviceConnection = object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName, service: IBinder) {
                debug("bindToService onServiceConnected")
                remoteServiceProxy = TestInterface.Stub.asInterface(service)
                remoteServiceProxy!!.registerServiceCallback(serviceConnectCallback)
                remoteServiceProxy!!.registerReceiveMessageCallback(receiveMessageCallback)
                callback.invoke(true)
            }

            override fun onServiceDisconnected(name: ComponentName) {
                debug("bindToService onServiceDisconnected")
                release()
            }
        }
        val result = application.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
        if (!result) {
            callback.invoke(false)
        }
    }

    suspend fun bindToService(): Boolean = withContext(Dispatchers.Default) {
        return@withContext suspendCoroutine { continuation ->
            bindToService { continuation.resume(it) }
        }
    }

    private fun release() {
        remoteServiceProxy = null
    }
}

