package com.joe.camera.webcam.system

import android.content.ComponentName
import android.content.Context
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.os.IBinder
import com.joe.camera.webcam.BuildConfig
import com.joe.camera.webcam.IUserService
import com.joe.camera.webcam.UserService
import com.joe.camera.webcam.model.ScreenControlMode
import rikka.shizuku.Shizuku

class ScreenController(private val context: Context) {
    private var service: IUserService? = null
    private val args = Shizuku.UserServiceArgs(ComponentName(BuildConfig.APPLICATION_ID, UserService::class.java.name)).daemon(false).processNameSuffix("screen").debuggable(BuildConfig.DEBUG).version(BuildConfig.VERSION_CODE)
    private val connection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, binder: IBinder?) { service = IUserService.Stub.asInterface(binder) }
        override fun onServiceDisconnected(name: ComponentName?) { service = null }
    }
    private val permissionListener = Shizuku.OnRequestPermissionResultListener { requestCode, grantResult ->
        if (requestCode == 42 && grantResult == PackageManager.PERMISSION_GRANTED) runCatching { Shizuku.bindUserService(args, connection) }
    }
    private val binderListener = Shizuku.OnBinderReceivedListener {
        if (Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) runCatching { Shizuku.bindUserService(args, connection) }
        else Shizuku.requestPermission(42)
    }

    fun prepare() {
        runCatching {
            Shizuku.addRequestPermissionResultListener(permissionListener)
            Shizuku.addBinderReceivedListenerSticky(binderListener)
            if (Shizuku.pingBinder() && Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) Shizuku.bindUserService(args, connection)
            else if (Shizuku.pingBinder()) Shizuku.requestPermission(42)
        }
    }

    fun setPhysicalScreen(off: Boolean): ScreenControlMode {
        val mode = if (off) 0 else 2
        if (service != null && runCatching { service?.setDisplayPowerMode(mode) == true }.getOrDefault(false)) return ScreenControlMode.SHIZUKU
        if (hasRoot()) {
            val apk = context.applicationInfo.sourceDir.replace("'", "'\\''")
            val command = "CLASSPATH='$apk' app_process / com.joe.camera.webcam.system.DisplayToggle $mode"
            if (runCatching { Runtime.getRuntime().exec(arrayOf("su", "-c", command)).waitFor() == 0 }.getOrDefault(false)) return ScreenControlMode.ROOT
        }
        return ScreenControlMode.OVERLAY
    }

    private fun hasRoot(): Boolean = runCatching { Runtime.getRuntime().exec(arrayOf("su", "-c", "id")).waitFor() == 0 }.getOrDefault(false)
    fun release() { runCatching { Shizuku.unbindUserService(args, connection, true) }; runCatching { Shizuku.removeRequestPermissionResultListener(permissionListener) }; runCatching { Shizuku.removeBinderReceivedListener(binderListener) }; service = null }
}
