package com.example.modifier.service

import android.accessibilityservice.AccessibilityService
import android.accessibilityservice.GestureDescription
import android.content.Intent
import android.graphics.Path
import android.graphics.Rect
import android.provider.Settings
import android.util.Log
import android.view.accessibility.AccessibilityNodeInfo
import androidx.core.content.ContextCompat
import com.example.modifier.R
import com.example.modifier.TraverseResult
import com.example.modifier.constants.CMD_BACK
import com.example.modifier.constants.CMD_RCS_SETTINGS_ACTIVITY
import com.example.modifier.utils.currentActivity
import com.example.modifier.utils.findAllScrollable
import com.example.modifier.utils.findFirstByIdAndText
import com.example.modifier.utils.shellRun
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull

class ScreenController(val context: AccessibilityService, private val inspector: ScreenInspector) {

    companion object {
        private const val TAG = "ScreenController"
    }

    suspend fun toggleRcsSwitch(state: Boolean, retry: Int = 3): Boolean {
        val res = TraverseResult()

        shellRun(CMD_RCS_SETTINGS_ACTIVITY, "sleep 2")
        val success = run repeatBlock@{
            repeat(retry) {
                res.rcsSwitch = null
                inspector.traverseNode(res)
                if (res.rcsSwitch == null) {
                    shellRun(CMD_BACK, "sleep 0.5", CMD_RCS_SETTINGS_ACTIVITY, "sleep 2")
                } else {
                    if (res.rcsSwitch!!.isChecked == state) {
                        return@repeatBlock true
                    }
                    val rect = Rect()
                    res.rcsSwitch!!.getBoundsInScreen(rect)
                    if (state) {
                        shellRun(
                            "input tap ${rect.centerX()} ${rect.centerY()}", "sleep 1",
                        )
                        val btn =
                            context.rootInActiveWindow.findAccessibilityNodeInfosByViewId("android:id/button1")
                                .firstOrNull()
                        if (btn != null) {
                            btn.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                            delay(1000)
                        }
                        while (currentActivity()?.contains("RcsSettingsActivity") == true ||
                            currentActivity()?.contains("TurnOffRcsActivity") == true
                        ) {
                            shellRun(CMD_BACK)
                            delay(500)
                        }
                        shellRun(CMD_RCS_SETTINGS_ACTIVITY, "sleep 1")
                    } else {
                        shellRun(
                            "input tap ${rect.centerX()} ${rect.centerY()}", "sleep 1",
                        )
                        if (currentActivity()?.contains("TurnOffRcsActivity") == true) {
                            inspector.traverseNode(res)
                            if (res.closeBtn != null) {
                                val rect1 = Rect()
                                res.closeBtn!!.getBoundsInScreen(rect1)
                                shellRun(
                                    "input tap ${rect1.centerX()} ${rect1.centerY()}", "sleep 1",
                                )
                            }
                        } else {
                            context.rootInActiveWindow.findAccessibilityNodeInfosByViewId("android:id/button1")
                                .firstOrNull()?.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                        }
                        delay(1000)
                        while (currentActivity()?.contains("RcsSettingsActivity") == true ||
                            currentActivity()?.contains("TurnOffRcsActivity") == true
                        ) {
                            shellRun(CMD_BACK)
                            delay(500)
                        }
                        shellRun(CMD_RCS_SETTINGS_ACTIVITY, "sleep 1")
                    }
                    res.rcsSwitch = null
                    inspector.traverseNode(res)
                    if (res.rcsSwitch?.isChecked == state) {
                        return@repeatBlock true
                    }
                }
            }
            false
        }
        while (currentActivity()?.contains("RcsSettingsActivity") == true) {
            shellRun(CMD_BACK)
            delay(500)
        }
        return success
    }

    suspend fun enableAdbWifi(): Boolean {
        val i = Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        context.startActivity(i)
        delay(500)
        var node: AccessibilityNodeInfo? = withTimeoutOrNull(10000) {
            repeat(999) {
                var n = context.rootInActiveWindow.findFirstByIdAndText(
                    "android:id/title",
                    "Wireless debugging", "无线调试"
                )
                if (n != null) {
                    return@withTimeoutOrNull n
                }
                context.rootInActiveWindow.findAllScrollable().forEach {
                    it.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)
                }
                delay(500)
            }
            return@withTimeoutOrNull null
        }
        if (node == null) {
            Log.e(TAG, "not found wireless debugging menu")
            return false
        }
        Log.i(TAG, "found wireless debugging menu")
        tapNode(node)
        delay(1000)

        val switchParent = context.rootInActiveWindow
            .findAccessibilityNodeInfosByViewId("com.android.settings:id/switch_bar")
            .firstOrNull()
        if (switchParent == null) {
            Log.e(TAG, "not found wireless debugging switch")
            return false
        }

        val switch = switchParent
            .findAccessibilityNodeInfosByViewId("android:id/switch_widget").firstOrNull()
        if (switch == null) {
            Log.e(TAG, "not found wireless debugging switch")
            return false
        }

        if (switch.isChecked) {
            Log.i(TAG, "wireless debugging is already enabled")
        } else {
            Log.i(TAG, "wireless debugging is disabled")
            switchParent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
            delay(1000)
        }

        node = context.rootInActiveWindow.findFirstByIdAndText(
            "android:id/title",
            "Pair device with pairing code", "使用配对码配对设备"
        )
        if (node == null) {
            Log.e(TAG, "not found pair device with pairing code")
            return false
        }
        Log.i(TAG, "found pair device with pairing code")
        node.parent.parent.performAction(AccessibilityNodeInfo.ACTION_CLICK)

        delay(1000)
        context.rootInActiveWindow.findFirstByIdAndText("android:id/title", "IP address & Port")
        return true
    }

    fun tapNode(node: AccessibilityNodeInfo) {
        val rect = Rect()
        node.getBoundsInScreen(rect)
        val path = Path()
        path.moveTo(rect.centerX().toFloat(), rect.centerY().toFloat())
        context.dispatchGesture(
            GestureDescription.Builder().addStroke(
                GestureDescription.StrokeDescription(path, 0, 100)
            ).build(), null, null
        )
    }

    suspend fun allowDebugging() {
        delay(300)
        context.rootInActiveWindow.findAccessibilityNodeInfosByViewId("android:id/alwaysUse")
            .find { !it.isChecked }?.performAction(AccessibilityNodeInfo.ACTION_CLICK)
        delay(200)
        context.rootInActiveWindow.findAccessibilityNodeInfosByViewId("android:id/button1")
            .firstOrNull()?.performAction(AccessibilityNodeInfo.ACTION_CLICK)
        delay(200)
    }

    suspend fun switchDefaultSmsApp(google: Boolean = false) {
        delay(300)
        val appName = ContextCompat.getString(context, R.string.app_name)
        Log.i(TAG, "set $appName as default sms app")
        val nodes =
            context.rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.android.permissioncontroller:id/title_and_subtitle")
        Log.i(TAG, "found ${nodes.size} title_and_subtitle")
        val node = nodes.find {
            if (google) it.findAccessibilityNodeInfosByText("信息").isNotEmpty()
                    || it.findAccessibilityNodeInfosByText("Messages").isNotEmpty()
            else it.findAccessibilityNodeInfosByText(appName).isNotEmpty()
        }
        if (node == null) {
            Log.e(TAG, "not found $appName")
            return
        }
        Log.i(TAG, "found $appName")
        node.parent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
    }
}