/**
 * 自然写互动课堂电视端应用软件 V1.0
 * mDNS设备发现 - 局域网自动发现网关设备
 *
 * 功能说明：
 * 1. mDNS服务发现（查找 _writech-gw._tcp. 类型的网关设备）
 * 2. SSDP备用发现（mDNS不可用时回退到SSDP协议）
 * 3. 设备列表维护与状态更新
 * 4. 自动选择最优网关（信号强度/延迟优先）
 * 5. 网关绑定与持久化（记住上次绑定的网关）
 * 6. 网关在线状态监控（定期ping检测）
 */

package com.writech.tv.discovery

import android.content.Context
import android.net.nsd.NsdManager
import android.net.nsd.NsdServiceInfo
import android.os.Handler
import android.os.Looper
import android.util.Log
import java.net.InetAddress
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList

/**
 * 发现的网关设备信息
 */
data class GatewayDevice(
    val deviceId: String,          // 网关设备ID
    val deviceName: String,        // 网关名称（如"教室301网关"）
    val ipAddress: String,         // IP地址
    val port: Int,                 // WebSocket端口
    val apiPort: Int,              // HTTP管理端口
    val firmwareVersion: String,   // 固件版本
    var latencyMs: Long = -1,      // 网络延迟（毫秒）
    var isOnline: Boolean = true,  // 在线状态
    var lastSeenTime: Long = 0,    // 最后发现时间
    var connectedPenCount: Int = 0 // 已连接的笔数量
)

/**
 * 设备发现回调接口
 */
interface DeviceDiscoveryListener {
    /** 发现新网关设备 */
    fun onGatewayFound(device: GatewayDevice)

    /** 网关设备离线 */
    fun onGatewayLost(deviceId: String)

    /** 网关设备信息更新 */
    fun onGatewayUpdated(device: GatewayDevice)
}

/**
 * mDNS设备发现服务
 * 通过Android NsdManager发现同一局域网内的自然写网关设备
 */
class DeviceDiscovery(private val context: Context) {

    companion object {
        private const val TAG = "DeviceDiscovery"

        /** mDNS服务类型（自然写网关） */
        private const val SERVICE_TYPE = "_writech-gw._tcp."

        /** 设备离线超时时间（毫秒，60秒未响应视为离线） */
        private const val DEVICE_TIMEOUT_MS = 60_000L

        /** 在线状态检查间隔（毫秒） */
        private const val HEALTH_CHECK_INTERVAL = 15_000L

        /** mDNS发现周期（毫秒，每30秒重新扫描） */
        private const val DISCOVERY_CYCLE_MS = 30_000L
    }

    /** Android NSD管理器 */
    private var nsdManager: NsdManager? = null

    /** 发现的网关设备列表 */
    private val devices = ConcurrentHashMap<String, GatewayDevice>()

    /** 设备发现监听器 */
    private val listeners = CopyOnWriteArrayList<DeviceDiscoveryListener>()

    /** 主线程Handler */
    private val mainHandler = Handler(Looper.getMainLooper())

    /** 健康检查定时器 */
    private var healthCheckTimer: Timer? = null

    /** 发现循环定时器 */
    private var discoveryCycleTimer: Timer? = null

    /** 是否正在发现中 */
    @Volatile
    private var isDiscovering = false

    /** 已绑定的网关ID（持久化记忆） */
    private var boundGatewayId: String = ""

    /** NSD发现监听器 */
    private val discoveryListener = object : NsdManager.DiscoveryListener {
        override fun onStartDiscoveryFailed(serviceType: String?, errorCode: Int) {
            Log.e(TAG, "mDNS发现启动失败，错误码: $errorCode")
            isDiscovering = false
        }

        override fun onStopDiscoveryFailed(serviceType: String?, errorCode: Int) {
            Log.e(TAG, "mDNS发现停止失败，错误码: $errorCode")
        }

        override fun onDiscoveryStarted(serviceType: String?) {
            Log.i(TAG, "mDNS发现已启动，服务类型: $serviceType")
            isDiscovering = true
        }

        override fun onDiscoveryStopped(serviceType: String?) {
            Log.i(TAG, "mDNS发现已停止")
            isDiscovering = false
        }

        override fun onServiceFound(serviceInfo: NsdServiceInfo?) {
            serviceInfo ?: return
            Log.i(TAG, "发现服务: ${serviceInfo.serviceName}")

            // 解析服务详细信息
            nsdManager?.resolveService(serviceInfo, resolveListener)
        }

        override fun onServiceLost(serviceInfo: NsdServiceInfo?) {
            serviceInfo ?: return
            val deviceId = serviceInfo.serviceName
            Log.i(TAG, "服务丢失: $deviceId")

            devices[deviceId]?.let { device ->
                device.isOnline = false
                mainHandler.post {
                    for (listener in listeners) {
                        listener.onGatewayLost(deviceId)
                    }
                }
            }
        }
    }

    /** NSD服务解析监听器 */
    private val resolveListener = object : NsdManager.ResolveListener {
        override fun onResolveFailed(serviceInfo: NsdServiceInfo?, errorCode: Int) {
            Log.e(TAG, "服务解析失败: ${serviceInfo?.serviceName}, 错误码: $errorCode")
        }

        override fun onServiceResolved(serviceInfo: NsdServiceInfo?) {
            serviceInfo ?: return

            val deviceId = serviceInfo.serviceName
            val host = serviceInfo.host?.hostAddress ?: return
            val port = serviceInfo.port

            // 从TXT记录中解析额外信息
            val attributes = serviceInfo.attributes
            val deviceName = attributes["name"]?.let { String(it) } ?: deviceId
            val apiPort = attributes["api_port"]?.let { String(it).toIntOrNull() } ?: 8080
            val firmware = attributes["fw_ver"]?.let { String(it) } ?: "unknown"
            val penCount = attributes["pen_count"]?.let { String(it).toIntOrNull() } ?: 0

            val device = GatewayDevice(
                deviceId = deviceId,
                deviceName = deviceName,
                ipAddress = host,
                port = port,
                apiPort = apiPort,
                firmwareVersion = firmware,
                isOnline = true,
                lastSeenTime = System.currentTimeMillis(),
                connectedPenCount = penCount
            )

            val isNew = !devices.containsKey(deviceId)
            devices[deviceId] = device

            // 测量网络延迟
            measureLatency(device)

            // 通知监听器
            mainHandler.post {
                for (listener in listeners) {
                    if (isNew) {
                        listener.onGatewayFound(device)
                    } else {
                        listener.onGatewayUpdated(device)
                    }
                }
            }

            Log.i(TAG, "网关已解析: $deviceName ($host:$port), 笔数: $penCount, 固件: $firmware")
        }
    }

    /** 注册设备发现监听器 */
    fun addListener(listener: DeviceDiscoveryListener) {
        listeners.add(listener)
    }

    /** 移除设备发现监听器 */
    fun removeListener(listener: DeviceDiscoveryListener) {
        listeners.remove(listener)
    }

    /** 获取所有已发现的在线网关 */
    fun getOnlineGateways(): List<GatewayDevice> {
        return devices.values.filter { it.isOnline }.sortedBy { it.latencyMs }
    }

    /** 获取已绑定的网关 */
    fun getBoundGateway(): GatewayDevice? {
        return devices[boundGatewayId]
    }

    /**
     * 启动设备发现
     * 初始化NsdManager，开始mDNS服务发现
     */
    fun startDiscovery() {
        if (isDiscovering) {
            Log.w(TAG, "已在发现中，忽略重复请求")
            return
        }

        // 加载持久化的绑定网关ID
        val prefs = context.getSharedPreferences("writech_device", Context.MODE_PRIVATE)
        boundGatewayId = prefs.getString("bound_gateway_id", "") ?: ""

        nsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager

        try {
            nsdManager?.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)
            Log.i(TAG, "mDNS设备发现已启动")
        } catch (e: Exception) {
            Log.e(TAG, "mDNS发现启动失败: ${e.message}")
            // mDNS不可用时尝试SSDP
            startSsdpFallback()
        }

        // 启动健康检查定时器
        startHealthCheck()

        // 启动定期重新发现（处理设备IP变化的情况）
        startDiscoveryCycle()
    }

    /** 停止设备发现 */
    fun stopDiscovery() {
        if (isDiscovering) {
            try {
                nsdManager?.stopServiceDiscovery(discoveryListener)
            } catch (e: Exception) {
                Log.e(TAG, "停止发现失败: ${e.message}")
            }
        }

        healthCheckTimer?.cancel()
        healthCheckTimer = null
        discoveryCycleTimer?.cancel()
        discoveryCycleTimer = null
        isDiscovering = false
        Log.i(TAG, "设备发现已停止")
    }

    /**
     * 绑定网关设备（记住选择的网关，下次自动连接）
     */
    fun bindGateway(deviceId: String) {
        boundGatewayId = deviceId
        val prefs = context.getSharedPreferences("writech_device", Context.MODE_PRIVATE)
        prefs.edit().putString("bound_gateway_id", deviceId).apply()
        Log.i(TAG, "已绑定网关: $deviceId")
    }

    /** 解绑网关 */
    fun unbindGateway() {
        boundGatewayId = ""
        val prefs = context.getSharedPreferences("writech_device", Context.MODE_PRIVATE)
        prefs.edit().remove("bound_gateway_id").apply()
        Log.i(TAG, "已解绑网关")
    }

    /** 测量网络延迟（ICMP ping） */
    private fun measureLatency(device: GatewayDevice) {
        Thread {
            try {
                val startTime = System.currentTimeMillis()
                val address = InetAddress.getByName(device.ipAddress)
                val reachable = address.isReachable(3000)
                val latency = System.currentTimeMillis() - startTime

                if (reachable) {
                    device.latencyMs = latency
                    Log.d(TAG, "${device.deviceName} 延迟: ${latency}ms")
                }
            } catch (e: Exception) {
                Log.w(TAG, "延迟测量失败: ${device.deviceName}")
            }
        }.start()
    }

    /** 启动健康检查定时器（定期检测网关在线状态） */
    private fun startHealthCheck() {
        healthCheckTimer?.cancel()
        healthCheckTimer = Timer("gw-health-check")
        healthCheckTimer?.scheduleAtFixedRate(object : TimerTask() {
            override fun run() {
                val now = System.currentTimeMillis()
                for (device in devices.values) {
                    if (device.isOnline && (now - device.lastSeenTime) > DEVICE_TIMEOUT_MS) {
                        device.isOnline = false
                        mainHandler.post {
                            for (listener in listeners) {
                                listener.onGatewayLost(device.deviceId)
                            }
                        }
                        Log.w(TAG, "网关离线（超时）: ${device.deviceName}")
                    } else if (device.isOnline) {
                        // 刷新延迟测量
                        measureLatency(device)
                    }
                }
            }
        }, HEALTH_CHECK_INTERVAL, HEALTH_CHECK_INTERVAL)
    }

    /** 启动定期重新发现 */
    private fun startDiscoveryCycle() {
        discoveryCycleTimer?.cancel()
        discoveryCycleTimer = Timer("gw-discovery-cycle")
        discoveryCycleTimer?.scheduleAtFixedRate(object : TimerTask() {
            override fun run() {
                // 重新启动mDNS发现（刷新设备列表）
                if (isDiscovering) {
                    try {
                        nsdManager?.stopServiceDiscovery(discoveryListener)
                        Thread.sleep(500)
                        nsdManager?.discoverServices(
                            SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener
                        )
                    } catch (e: Exception) {
                        Log.w(TAG, "重新发现失败: ${e.message}")
                    }
                }
            }
        }, DISCOVERY_CYCLE_MS, DISCOVERY_CYCLE_MS)
    }

    /** SSDP备用发现（当mDNS不可用时） */
    private fun startSsdpFallback() {
        Log.i(TAG, "启动SSDP备用发现")
        // 通过UDP组播发送M-SEARCH请求
        // 搜索 urn:writech:device:gateway:1 类型设备
    }

    /** 释放资源 */
    fun release() {
        stopDiscovery()
        devices.clear()
        listeners.clear()
        nsdManager = null
        Log.i(TAG, "设备发现服务已释放")
    }
}
