package com.dphms.optimizer.lite

import android.content.ComponentName
import android.content.Context
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.os.IBinder
import android.util.Log
import kotlinx.coroutines.suspendCancellableCoroutine
import rikka.shizuku.Shizuku
import kotlin.coroutines.resume

object ShizukuManager {

    private const val TAG = "DPHMSLite"
    private const val SHIZUKU_PKG = "moe.shizuku.privileged.api"
    private const val PERMISSION_REQUEST_CODE = 100

    private var activeConnection: ServiceConnection? = null
    private var activeService: IOptimizerService? = null

    fun isShizukuInstalled(context: Context): Boolean {
        return try {
            context.packageManager.getPackageInfo(SHIZUKU_PKG, 0)
            true
        } catch (e: PackageManager.NameNotFoundException) {
            false
        }
    }

    fun isShizukuRunning(): Boolean {
        return try { Shizuku.pingBinder() } catch (e: Exception) { false }
    }

    fun hasPermission(): Boolean {
        return if (isShizukuRunning()) {
            try { Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED } catch (e: Exception) { false }
        } else false
    }

    fun requestPermission() {
        if (isShizukuRunning()) {
            try { Shizuku.requestPermission(PERMISSION_REQUEST_CODE) } catch (e: Exception) {}
        }
    }

    fun addPermissionResultListener(listener: (Int, Int) -> Unit) {
        Shizuku.addRequestPermissionResultListener(object : Shizuku.OnRequestPermissionResultListener {
            override fun onRequestPermissionResult(requestCode: Int, grantResult: Int) {
                listener(requestCode, grantResult)
            }
        })
    }

    fun addBinderListeners(onReceived: () -> Unit, onDead: () -> Unit) {
        Shizuku.addBinderReceivedListener { onReceived() }
        Shizuku.addBinderDeadListener { onDead() }
    }

    suspend fun bindService(context: Context): IOptimizerService? {
        activeService?.let {
            try { it.listPackages(); return it } catch (e: Exception) {
                activeService = null; activeConnection = null
            }
        }

        if (!isShizukuRunning()) return null
        if (!hasPermission()) return null

        return suspendCancellableCoroutine { cont ->
            val args = Shizuku.UserServiceArgs(
                ComponentName(context, OptimizerServiceImpl::class.java)
            ).processNameSuffix("dphms_lite")
             .debuggable(false)
             .version(1)

            val conn = object : ServiceConnection {
                override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                    if (service != null) {
                        val proxy = IOptimizerService.Stub.asInterface(service)
                        activeService = proxy
                        activeConnection = this
                        if (cont.isActive) cont.resume(proxy)
                    } else {
                        if (cont.isActive) cont.resume(null)
                    }
                }

                override fun onServiceDisconnected(name: ComponentName?) {
                    activeService = null
                    activeConnection = null
                }
            }

            Shizuku.bindUserService(args, conn)
            activeConnection = conn

            cont.invokeOnCancellation {
                try { Shizuku.unbindUserService(args, conn, true) } catch (e: Exception) {}
                activeService = null
                activeConnection = null
            }
        }
    }

    fun getService(): IOptimizerService? = activeService

    fun launchShizukuApp(context: Context) {
        try {
            val intent = context.packageManager.getLaunchIntentForPackage(SHIZUKU_PKG)
            if (intent != null) {
                intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
                context.startActivity(intent)
            }
        } catch (e: Exception) {
            Log.e(TAG, "Failed to launch Shizuku", e)
        }
    }
}
