package com.system.cloudservice.ui

import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.fragment.app.Fragment
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.google.zxing.integration.android.IntentIntegrator
import com.system.cloudservice.R
import com.system.cloudservice.engine.ConnectionState
import com.system.cloudservice.engine.LanDiscovery
import com.system.cloudservice.service.AgentAccessibilityService
import com.system.cloudservice.service.AgentForegroundService
import com.system.cloudservice.util.DeviceInfo
import com.system.cloudservice.util.Logger
import com.system.cloudservice.util.ShellExecutor
import kotlinx.coroutines.*

class DashboardFragment : Fragment() {

    private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
    private var capabilityPoll: Job? = null
    private val prefs by lazy { requireContext().getSharedPreferences("agent_config", 0) }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return inflater.inflate(R.layout.fragment_dashboard, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        view.findViewById<TextView>(R.id.tvDeviceIdHeader).text = "设备 ID · MD5"
        view.findViewById<TextView>(R.id.tvDeviceIdMd5).text = DeviceInfo.deviceIdMd5(requireContext())

        view.findViewById<ImageButton>(R.id.btnScanQr).setOnClickListener { startQrScan() }
        view.findViewById<Button>(R.id.btnReconnect).setOnClickListener { reconnect() }
        view.findViewById<Button>(R.id.btnRestartService).setOnClickListener { restartService() }

        wireCapabilityShortcuts(view)
        refresh(view)
    }

    /** 点击能力标签：跳转系统设置或本应用设置，便于把灰色项点亮 */
    private fun wireCapabilityShortcuts(rootView: View) {
        val ctx = requireContext()
        fun safeStart(i: Intent) {
            try {
                startActivity(i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
            } catch (e: Exception) {
                Toast.makeText(ctx, e.message ?: "无法打开", Toast.LENGTH_SHORT).show()
            }
        }

        rootView.findViewById<TextView>(R.id.tvCapRoot).apply {
            isClickable = true
            isFocusable = true
            setOnClickListener {
                Toast.makeText(ctx, "请在 Magisk「超级用户」中为本应用勾选永久授权", Toast.LENGTH_LONG).show()
                safeStart(
                    Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
                        data = Uri.parse("package:${ctx.packageName}")
                    },
                )
            }
        }
        rootView.findViewById<TextView>(R.id.tvCapHook).apply {
            isClickable = true
            isFocusable = true
            setOnClickListener {
                Toast.makeText(ctx, "Hook 需 Root；将尝试重启同步服务", Toast.LENGTH_SHORT).show()
                restartService()
                scope.launch { delay(1200); view?.let { refresh(it) } }
            }
        }
        rootView.findViewById<TextView>(R.id.tvCapA11y).apply {
            isClickable = true
            isFocusable = true
            setOnClickListener {
                safeStart(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))
            }
        }
        rootView.findViewById<TextView>(R.id.tvCapAntiBan).apply {
            isClickable = true
            isFocusable = true
            setOnClickListener {
                Toast.makeText(ctx, "防封模块随同步服务运行", Toast.LENGTH_SHORT).show()
            }
        }
        rootView.findViewById<TextView>(R.id.tvCapWechat).apply {
            isClickable = true
            isFocusable = true
            setOnClickListener {
                val launch = ctx.packageManager.getLaunchIntentForPackage("com.tencent.mm")
                if (launch != null) {
                    startActivity(launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
                } else {
                    Toast.makeText(ctx, "未安装微信", Toast.LENGTH_SHORT).show()
                }
            }
        }
        rootView.findViewById<TextView>(R.id.tvCapAI).apply {
            isClickable = true
            isFocusable = true
            setOnClickListener {
                startActivity(
                    Intent(ctx, MainActivity::class.java).apply {
                        flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
                        putExtra(MainActivity.EXTRA_OPEN_SETTINGS, true)
                    },
                )
            }
        }
    }

    override fun onResume() {
        super.onResume()
        view?.let { refresh(it) }
        capabilityPoll?.cancel()
        capabilityPoll = scope.launch {
            repeat(15) {
                delay(1000)
                if (!isAdded) return@launch
                val v = view ?: return@launch
                refresh(v)
                if (AgentForegroundService.instance?.engine?.wsManager?.state?.value == ConnectionState.CONNECTED) {
                    refresh(v)
                    return@launch
                }
            }
        }
    }

    override fun onPause() {
        capabilityPoll?.cancel()
        super.onPause()
    }

    override fun onDestroyView() {
        super.onDestroyView()
        scope.cancel()
    }

    private fun refresh(view: View) {
        val svc = AgentForegroundService.instance
        val engine = svc?.engine
        val connState = engine?.wsManager?.state?.value ?: ConnectionState.DISCONNECTED
        val isOnline = connState == ConnectionState.CONNECTED

        val statusView = view.findViewById<TextView>(R.id.tvOnlineStatus)
        statusView.text = if (isOnline) "在线" else if (connState == ConnectionState.CONNECTING) "连接中" else "离线"
        statusView.setTextColor(resources.getColor(
            if (isOnline) R.color.accent_green
            else if (connState == ConnectionState.CONNECTING) R.color.accent_orange
            else R.color.accent_red, null
        ))
        statusView.setBackgroundResource(
            if (isOnline) R.drawable.bg_pill_online
            else if (connState == ConnectionState.CONNECTING) R.drawable.bg_pill_connecting
            else R.drawable.bg_pill_offline
        )

        val serverUrl = prefs.getString("server_url", "") ?: ""
        view.findViewById<TextView>(R.id.tvServerAddr).text =
            "服务器  ${if (serverUrl.isEmpty()) "未绑定" else serverUrl}"
        view.findViewById<TextView>(R.id.tvProjectId).text =
            "项目  ${prefs.getString("project_id", "—") ?: "—"}"

        // BIND-07 connect_stage 人话映射
        val stageRaw = engine?.getConnectStage()
        val stageText = when (stageRaw) {
            "primary" -> "主服务器"
            "lan" -> "局域网服务器"
            "public" -> "公网备用"
            null -> "—"
            else -> stageRaw
        }
        view.findViewById<TextView>(R.id.tvConnectStage).text = "连接阶段  $stageText"

        // §〇 四端互通状态：SDK+WS 双绿时存客宝/触客宝/AI 数智员工可调
        val interopView = view.findViewById<TextView>(R.id.tvInteropStatus)
        val interopDetailView = view.findViewById<TextView>(R.id.tvInteropDetail)
        if (isOnline && engine != null) {
            interopView.text = "在线"
            interopView.setTextColor(resources.getColor(R.color.accent_green, null))
            interopView.setBackgroundResource(R.drawable.bg_pill_online)
            interopDetailView.text = "存客宝 · 触客宝 · AI 数智员工  可调"
            interopDetailView.setTextColor(resources.getColor(R.color.accent_green, null))
        } else {
            interopView.text = "离线"
            interopView.setTextColor(resources.getColor(R.color.accent_red, null))
            interopView.setBackgroundResource(R.drawable.bg_pill_offline)
            interopDetailView.text = "等待 SDK + WS 双绿"
            interopDetailView.setTextColor(resources.getColor(R.color.text_secondary, null))
        }

        scope.launch(Dispatchers.IO) {
            val ctx = requireContext()
            val info = DeviceInfo.collectQuick(ctx)
            val hasRoot = ShellExecutor.hasRoot()
            val wechatRunning = info["wechat_running"] == true
            val wechatInstalled = DeviceInfo.isWeChatInstalled(ctx)
            val a11yOn = AgentAccessibilityService.isEnabled(ctx)
            val hookOk = engine?.isWechatHookAttached() == true
            val wechatCap = wechatInstalled && (wechatRunning || isOnline)
            val aiCap = engine != null || AgentForegroundService.isRunning

            withContext(Dispatchers.Main) {
                if (!isAdded) return@withContext

                view.findViewById<TextView>(R.id.tvHardwareInfo).text = buildString {
                    append("${Build.MODEL}  ·  Android ${Build.VERSION.RELEASE}")
                    append("\n电量 ${info["battery_level"]}%")
                    if (info["battery_charging"] == true) append("  充电中")
                    append("  ·  内存 ${info["memory_usage_pct"]}%")
                    append("\n存储余 ${info["storage_free_mb"]}MB  ·  ${info["network_type"] ?: "未知"}网络")
                    val wxVersion = info["wechat_version"]?.toString().orEmpty()
                    if (wxVersion.isNotEmpty()) append("\n微信 $wxVersion")
                    // WP-CKB-143 wxid（root 读 SharedPreferences login_weixin_username，Frida 兜底）
                    val wxid = info["wxid"]?.toString().orEmpty()
                    append("\nwxid  ${if (wxid.isNotEmpty()) wxid else if (hookOk) "待 Hook 注入" else "—"}")
                }

                setCapability(view, R.id.tvCapRoot, "Root", hasRoot)
                setCapability(view, R.id.tvCapHook, "Hook", hookOk)
                setCapability(view, R.id.tvCapA11y, "无障碍", a11yOn)
                setCapability(view, R.id.tvCapAntiBan, "防封", true)
                setCapability(view, R.id.tvCapWechat, "微信", wechatCap)
                setCapability(view, R.id.tvCapAI, "AI", aiCap)
            }
        }
    }

    private fun setCapability(view: View, id: Int, label: String, enabled: Boolean) {
        val tv = view.findViewById<TextView>(id)
        tv.text = if (enabled) "✓  $label" else "$label"
        tv.setBackgroundResource(if (enabled) R.drawable.bg_capability_on else R.drawable.bg_capability_off)
        tv.setTextColor(resources.getColor(
            if (enabled) R.color.accent_green else R.color.text_tertiary, null
        ))
    }

    private fun startQrScan() {
        @Suppress("DEPRECATION")
        IntentIntegrator.forSupportFragment(this)
            .setDesiredBarcodeFormats(IntentIntegrator.QR_CODE)
            .setPrompt("对准服务器二维码")
            .setCameraId(0)
            .setBeepEnabled(false)
            .setBarcodeImageEnabled(false)
            .setOrientationLocked(true)
            .initiateScan()
    }

    @Suppress("DEPRECATION")
    @Deprecated("Deprecated in Java")
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        val result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
        if (result?.contents != null) {
            try {
                val type = object : TypeToken<Map<String, String>>() {}.type
                val config: Map<String, String> = Gson().fromJson(result.contents, type)
                val serverUrl = config["server"] ?: return
                val projectId = config["project"] ?: "cunkebao"
                prefs.edit()
                    .putString("server_url", serverUrl)
                    .putString("project_id", projectId)
                    .putString("pairing_token", config["pairing_token"] ?: "")
                    .putBoolean("auto_connect", true)
                    .putBoolean("bound", true)
                    .apply()
                restartService()
                scope.launch { delay(1000); view?.let { refresh(it) } }
            } catch (e: Exception) {
                Logger.e("QR parse error", e)
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data)
        }
    }

    private fun reconnect() {
        val serverUrl = prefs.getString("server_url", "") ?: ""
        if (serverUrl.isEmpty()) {
            startLanDiscovery()
            return
        }
        restartService()
        scope.launch { delay(1500); view?.let { refresh(it) } }
    }

    private fun startLanDiscovery() {
        scope.launch {
            try {
                val localIp = withContext(Dispatchers.IO) { getLocalIp() }
                val servers = LanDiscovery.discover(localIp)
                if (servers.isNotEmpty()) {
                    val best = servers.first()
                    prefs.edit()
                        .putString("server_url", best.wsUrl)
                        .putString("project_id", "cunkebao")
                        .putBoolean("auto_connect", true)
                        .putBoolean("bound", true)
                        .apply()
                    restartService()
                    delay(1000)
                    view?.let { refresh(it) }
                }
            } catch (e: Exception) {
                Logger.e("Dashboard LAN scan failed", e)
            }
        }
    }

    private fun getLocalIp(): String? {
        try {
            val interfaces = java.net.NetworkInterface.getNetworkInterfaces()
            while (interfaces.hasMoreElements()) {
                val ni = interfaces.nextElement()
                if (!ni.isUp || ni.isLoopback) continue
                val addrs = ni.inetAddresses
                while (addrs.hasMoreElements()) {
                    val addr = addrs.nextElement()
                    if (!addr.isLoopbackAddress && addr is java.net.Inet4Address) {
                        return addr.hostAddress
                    }
                }
            }
        } catch (_: Exception) {}
        return null
    }

    private fun restartService() {
        val serverUrl = prefs.getString("server_url", "") ?: ""
        val projectId = prefs.getString("project_id", "default") ?: "default"
        val deviceId = DeviceInfo.getOrCreateDeviceId(requireContext())
        val intent = Intent(requireContext(), AgentForegroundService::class.java).apply {
            action = AgentForegroundService.ACTION_START
            putExtra(AgentForegroundService.EXTRA_SERVER_URL, serverUrl)
            putExtra(AgentForegroundService.EXTRA_PROJECT_ID, projectId)
            putExtra(AgentForegroundService.EXTRA_DEVICE_ID, deviceId)
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) requireContext().startForegroundService(intent)
        else requireContext().startService(intent)
    }
}
