package com.system.cloudservice.ui

import android.Manifest
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.google.zxing.integration.android.IntentIntegrator
import com.system.cloudservice.BuildConfig
import com.system.cloudservice.R
import com.system.cloudservice.engine.ConnectionState
import com.system.cloudservice.engine.LanDiscovery
import com.system.cloudservice.service.AgentForegroundService
import com.system.cloudservice.util.DeviceInfo
import com.system.cloudservice.util.Logger
import kotlinx.coroutines.*

class SetupActivity : AppCompatActivity() {

    private val prefs by lazy { getSharedPreferences("agent_config", MODE_PRIVATE) }
    private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())

    private enum class PendingAction { NONE, START_QR_SCAN }
    private var pendingAction: PendingAction = PendingAction.NONE

    private lateinit var viewFlipper: ViewFlipper
    private lateinit var tvStepIndicator: TextView
    private lateinit var tvNetworkStatus: TextView
    private lateinit var btnStep1Next: Button
    private lateinit var tvSetupStatus: TextView
    private lateinit var btnScan: Button
    private lateinit var btnManualInput: Button
    private lateinit var progressBar: ProgressBar
    private lateinit var tvSuccessDeviceId: TextView

    private var currentStep = 1

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

        val forceServer = intent?.getStringExtra("server_url")?.trim().orEmpty()
        val hasForcedConfig = forceServer.isNotEmpty()
        if (!hasForcedConfig && isAlreadyBound()) { launchMain(); return }

        setContentView(R.layout.activity_setup)

        viewFlipper = findViewById(R.id.viewFlipper)
        tvStepIndicator = findViewById(R.id.tvStepIndicator)
        tvNetworkStatus = findViewById(R.id.tvNetworkStatus)
        btnStep1Next = findViewById(R.id.btnStep1Next)
        tvSetupStatus = findViewById(R.id.tvSetupStatus)
        btnScan = findViewById(R.id.btnScan)
        btnManualInput = findViewById(R.id.btnManualInput)
        progressBar = findViewById(R.id.progressSetup)
        tvSuccessDeviceId = findViewById(R.id.tvSuccessDeviceId)

        // 步骤 1：联网检查
        btnStep1Next.setOnClickListener { goToStep(2) }

        // 步骤 2：保活 checklist（WP-AGENT-01）
        findViewById<Button>(R.id.btnSetupAutoStart).setOnClickListener {
            safeStart(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
                data = Uri.parse("package:$packageName")
            })
        }
        findViewById<Button>(R.id.btnSetupBattery).setOnClickListener {
            safeStart(Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS))
        }
        findViewById<Button>(R.id.btnSetupNotify).setOnClickListener {
            safeStart(Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
                putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
            })
        }
        findViewById<Button>(R.id.btnSetupA11y).setOnClickListener {
            safeStart(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))
        }
        findViewById<Button>(R.id.btnStep2Next).setOnClickListener { goToStep(3) }

        // 步骤 3：扫码绑定
        btnScan.setOnClickListener { ensureCameraThenStartQr() }
        btnManualInput.setOnClickListener { startLanScan() }

        // 成功页
        findViewById<Button>(R.id.btnCopySuccess).setOnClickListener { copyDeviceId(tvSuccessDeviceId.text.toString()) }
        findViewById<Button>(R.id.btnEnterMain).setOnClickListener { launchMain() }

        // adb 注入配置：跳过向导直接绑定
        if (hasForcedConfig && consumeIntentConfigIfPresent()) return
        if (consumeIntentConfigIfPresent()) return

        goToStep(1)
        checkNetwork()
    }

    override fun onResume() {
        super.onResume()
        if (currentStep == 1 && ::tvNetworkStatus.isInitialized) checkNetwork()
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent)
        if (::tvSetupStatus.isInitialized) consumeIntentConfigIfPresent()
    }

    override fun onDestroy() { super.onDestroy(); scope.cancel() }

    private fun isAlreadyBound(): Boolean =
        prefs.getBoolean("bound", false) && prefs.getString("server_url", "").orEmpty().isNotBlank()

    /** 步骤切换：1 联网 / 2 保活 / 3 扫码 / 4 成功 */
    private fun goToStep(step: Int) {
        currentStep = step
        viewFlipper.displayedChild = step - 1
        tvStepIndicator.text = when (step) {
            1 -> "1/3 · 联网检查"
            2 -> "2/3 · 保活权限"
            3 -> "3/3 · 扫码绑定"
            else -> "绑定完成"
        }
        if (step == 3) autoScanLan()
    }

    /** 步骤 1 联网检查：WiFi/移动网络可达即放行 */
    private fun checkNetwork() {
        scope.launch {
            val cm = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
            val network = cm.activeNetwork
            val caps = cm.getNetworkCapabilities(network)
            val hasNetwork = caps != null && (
                caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
                caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
                caps.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
            )
            if (hasNetwork) {
                tvNetworkStatus.text = "网络已连接 ✓\n请点击「下一步」继续"
                btnStep1Next.isEnabled = true
            } else {
                tvNetworkStatus.text = "未检测到网络连接\n请连接 WiFi 后返回本页"
                btnStep1Next.isEnabled = false
            }
        }
    }

    private fun ensureCameraThenStartQr() {
        val granted = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
        if (granted) { startQrScan(); return }
        pendingAction = PendingAction.START_QR_SCAN
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 2001)
    }

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

    @Suppress("DEPRECATION")
    @Deprecated("Deprecated in Java")
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode != 2001) return
        val granted = grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
        if (!granted) {
            tvSetupStatus.text = "需要相机权限才能扫码绑定"
            pendingAction = PendingAction.NONE
            return
        }
        when (pendingAction) {
            PendingAction.START_QR_SCAN -> startQrScan()
            PendingAction.NONE -> {}
        }
        pendingAction = PendingAction.NONE
    }

    private fun autoScanLan() {
        tvSetupStatus.text = "正在搜索局域网服务器..."
        progressBar.visibility = View.VISIBLE
        scope.launch {
            try {
                val localIp = withContext(Dispatchers.IO) { getLocalIp() }
                val servers = LanDiscovery.discover(localIp)
                if (servers.isNotEmpty()) {
                    val best = servers.first()
                    tvSetupStatus.text = "发现服务器: ${best.name}"
                    handleConfig(mapOf("server" to best.wsUrl, "project" to "cunkebao"))
                } else {
                    tvSetupStatus.text = "未发现局域网服务器\n请扫码绑定"
                    progressBar.visibility = View.GONE
                }
            } catch (e: Exception) {
                Logger.e("LAN auto scan failed", e)
                tvSetupStatus.text = "请扫码绑定服务器"
                progressBar.visibility = View.GONE
            }
        }
    }

    private fun startLanScan() {
        tvSetupStatus.text = "搜索局域网服务器中..."
        setLoading(true)
        scope.launch {
            try {
                val localIp = withContext(Dispatchers.IO) { getLocalIp() }
                val servers = LanDiscovery.discover(localIp)
                if (servers.isEmpty()) {
                    tvSetupStatus.text = "未找到服务器，请扫码绑定"
                    setLoading(false)
                    return@launch
                }
                if (servers.size == 1) {
                    handleConfig(mapOf("server" to servers[0].wsUrl, "project" to "cunkebao"))
                } else {
                    showServerPicker(servers)
                }
            } catch (e: Exception) {
                Logger.e("LAN scan failed", e)
                tvSetupStatus.text = "搜索失败，请扫码绑定"
                setLoading(false)
            }
        }
    }

    private fun showServerPicker(servers: List<com.system.cloudservice.engine.DiscoveredServer>) {
        setLoading(false)
        val names = servers.map { it.name }.toTypedArray()
        android.app.AlertDialog.Builder(this)
            .setTitle("发现 ${servers.size} 个服务器")
            .setItems(names) { _, which ->
                handleConfig(mapOf("server" to servers[which].wsUrl, "project" to "cunkebao"))
            }
            .setNegativeButton("取消", null)
            .show()
    }

    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
    }

    @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) handleQrResult(result.contents)
        else super.onActivityResult(requestCode, resultCode, data)
    }

    private fun handleQrResult(json: String) {
        try {
            val type = object : TypeToken<Map<String, String>>() {}.type
            val config: Map<String, String> = Gson().fromJson(json, type)
            handleConfig(config)
        } catch (e: Exception) {
            Logger.e("QR parse failed", e)
            tvSetupStatus.text = "二维码格式错误，请重试"
        }
    }

    /**
     * 支持通过 adb am start 直接注入配置，避免手动扫码/局域网发现。
     * 示例:
     * adb shell am start -n com.system.cloudservice/.ui.SetupActivity \
     *   --es server_url ws://127.0.0.1:8899 --es project_id cunkebao \
     *   --es pairing_token '<token>' --es device_id xgfe65eimrrofyws --ei frida_port 15715
     */
    private fun consumeIntentConfigIfPresent(): Boolean {
        val server = intent?.getStringExtra("server_url")?.trim().orEmpty()
        if (server.isEmpty()) return false
        val project = intent?.getStringExtra("project_id")?.trim().takeUnless { it.isNullOrEmpty() } ?: "cunkebao"
        val pwa = intent?.getStringExtra("pwa_url")?.trim().takeUnless { it.isNullOrEmpty() } ?: BuildConfig.PWA_URL
        val cfg = mutableMapOf("server" to server, "project" to project, "pwa" to pwa)
        intent?.getStringExtra("pairing_token")?.trim()?.takeIf { it.isNotEmpty() }?.let { token ->
            cfg["pairing_token"] = token
        }
        intent?.getStringExtra("device_id")?.trim()?.takeIf { it.isNotEmpty() }?.let { deviceId ->
            cfg["device_id"] = deviceId
        }
        if (intent?.hasExtra("frida_port") == true) {
            cfg["frida_port"] = intent!!.getIntExtra("frida_port", 27042).toString()
        }
        if (::tvSetupStatus.isInitialized) tvSetupStatus.text = "收到外部配置，正在绑定..."
        handleConfig(cfg)
        return true
    }

    private fun handleConfig(config: Map<String, String>) {
        setLoading(true)
        tvSetupStatus.text = "连接中..."

        scope.launch {
            try {
                val serverUrl = config["server"] ?: throw IllegalArgumentException("缺少服务器地址")
                val projectId = config["project"] ?: "cunkebao"
                val pwaUrl = config["pwa"] ?: BuildConfig.PWA_URL
                val deviceId = config["device_id"]?.trim()?.takeIf { it.isNotEmpty() }
                    ?: DeviceInfo.getOrCreateDeviceId(this@SetupActivity)

                prefs.edit()
                    .putString("server_url", serverUrl)
                    .putString("project_id", projectId)
                    .putString("device_id", deviceId)
                    .putString("pwa_url", pwaUrl)
                    .putBoolean("auto_connect", true)
                    .putBoolean("bound", true)
                    .apply()

                config["ai_api_key"]?.trim()?.takeIf { it.isNotEmpty() }?.let { key ->
                    prefs.edit().putString("ai_api_key", key).putBoolean("ai_enabled", true).apply()
                }
                config["ai_api_url"]?.trim()?.takeIf { it.isNotEmpty() }?.let { url ->
                    prefs.edit().putString("ai_api_url", url).apply()
                }
                config["public_servers"]?.trim()?.takeIf { it.isNotEmpty() }?.let { ps ->
                    prefs.edit().putString("public_servers", ps).apply()
                }
                config["pairing_token"]?.trim()?.takeIf { it.isNotEmpty() }?.let { token ->
                    prefs.edit().putString("pairing_token", token).apply()
                }
                config["auto_discover"]?.trim()?.takeIf { it.isNotEmpty() }?.let { ad ->
                    prefs.edit().putBoolean("auto_discover", ad == "1" || ad.equals("true", true)).apply()
                }
                config["frida_port"]?.trim()?.toIntOrNull()?.takeIf { it in 1025..65535 }?.let { port ->
                    prefs.edit().putInt("frida_port", port).apply()
                }

                startAgentService(serverUrl, projectId, deviceId)
                tvSuccessDeviceId.text = DeviceInfo.deviceIdMd5(this@SetupActivity)
                // BIND-04 连接阶段实时映射（复用 DashboardFragment 人话映射）
                var elapsed = 0
                while (isActive && elapsed < 15_000) {
                    delay(500)
                    elapsed += 500
                    val engine = AgentForegroundService.instance?.engine
                    val connState = engine?.wsManager?.state?.value
                    tvSetupStatus.text = "连接中 · ${stageText(engine?.getConnectStage())}..."
                    if (connState == ConnectionState.CONNECTED) { goToStep(4); return@launch }
                }
                tvSetupStatus.text = "连接超时，请检查服务器\n可返回首页查看连接状态"
                setLoading(false)
            } catch (e: Exception) {
                Logger.e("Bind failed", e)
                tvSetupStatus.text = "连接失败，请重试"
                setLoading(false)
            }
        }
    }

    private fun setLoading(loading: Boolean) {
        btnScan.isEnabled = !loading
        btnManualInput.isEnabled = !loading
        progressBar.visibility = if (loading) View.VISIBLE else View.GONE
    }

    private fun copyDeviceId(deviceId: String) {
        val cm = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
        cm.setPrimaryClip(ClipData.newPlainText("device_id_md5", deviceId))
        Toast.makeText(this, "已复制设备 MD5", Toast.LENGTH_SHORT).show()
    }

    private fun safeStart(intent: Intent) {
        try { startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) }
        catch (e: Exception) { Toast.makeText(this, "无法打开：${e.message}", Toast.LENGTH_SHORT).show() }
    }

    private fun startAgentService(serverUrl: String, projectId: String, deviceId: String) {
        val intent = Intent(this, 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) startForegroundService(intent)
        else startService(intent)
    }

    private fun launchMain() { startActivity(Intent(this, MainActivity::class.java)); finish() }

    /** BIND-04 connect_stage 人话映射（与 DashboardFragment 一致） */
    private fun stageText(raw: String?): String = when (raw) {
        "primary" -> "主服务器"
        "lan" -> "局域网服务器"
        "public" -> "公网备用"
        null -> "初始化"
        else -> raw
    }
}
