/**
 * 自然写互动课堂智慧黑板端应用软件 V1.0
 *
 * GatewayConnector.kt - 网关WebSocket连接管理
 *
 * 功能说明：
 * - mDNS自动发现教室网关设备
 * - WebSocket连接管理（心跳/重连/消息路由）
 * - 笔迹数据流接收与分发
 * - 课堂控制指令发送
 * - 网关状态监控
 */

package com.writech.board.network

import android.content.Context
import android.net.nsd.NsdManager
import android.net.nsd.NsdServiceInfo
import android.util.Log
import org.json.JSONObject
import java.util.concurrent.*
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger

/**
 * 网关设备信息
 */
data class GatewayInfo(
    val gatewayId: String,            /* 网关唯一ID */
    val host: String,                 /* IP地址 */
    val port: Int,                    /* WebSocket端口 */
    val onlinePenCount: Int = 0,      /* 在线笔数量 */
    val firmwareVersion: String = "", /* 固件版本 */
    val signalStrength: Int = 0,      /* WiFi信号强度 */
    val lastHeartbeat: Long = System.currentTimeMillis()
)

/**
 * 网关连接状态
 */
enum class GatewayConnectionState {
    DISCONNECTED,    /* 未连接 */
    DISCOVERING,     /* 正在发现 */
    CONNECTING,      /* 连接中 */
    CONNECTED,       /* 已连接 */
    RECONNECTING     /* 重连中 */
}

/**
 * 网关消息类型
 */
object GatewayMessageType {
    const val STROKE = "stroke"          /* 笔迹数据 */
    const val EVENT = "event"            /* 设备事件 */
    const val STATUS = "status"          /* 网关状态 */
    const val COMMAND_ACK = "cmd_ack"    /* 命令应答 */
    const val HEARTBEAT = "heartbeat"    /* 心跳 */
}

/**
 * 网关消息回调接口
 */
interface GatewayMessageListener {
    fun onGatewayMessage(type: String, payload: JSONObject)
    fun onGatewayStateChanged(state: GatewayConnectionState, info: GatewayInfo?)
}

/**
 * 网关连接管理器
 *
 * 负责:
 * 1. 通过mDNS自动发现同一教室网关
 * 2. 建立WebSocket长连接
 * 3. 双向消息收发
 * 4. 自动重连机制
 */
class GatewayConnector(private val context: Context) {

    companion object {
        private const val TAG = "GatewayConnector"
        /** mDNS服务类型 */
        private const val MDNS_SERVICE_TYPE = "_writech-gw._tcp."
        /** 心跳间隔 */
        private const val HEARTBEAT_INTERVAL_MS = 15000L
        /** 重连基础延迟 */
        private const val RECONNECT_BASE_DELAY_MS = 3000L
        /** 最大重连延迟 */
        private const val RECONNECT_MAX_DELAY_MS = 60000L
        /** 心跳超时时间 */
        private const val HEARTBEAT_TIMEOUT_MS = 45000L
    }

    /* ==================== 连接状态 ==================== */

    /** 当前连接状态 */
    var connectionState = GatewayConnectionState.DISCONNECTED
        private set

    /** 当前连接的网关信息 */
    var currentGateway: GatewayInfo? = null
        private set

    /** 是否正在运行 */
    private val isRunning = AtomicBoolean(false)

    /** 重连尝试次数 */
    private val reconnectAttempts = AtomicInteger(0)

    /** 最后收到心跳的时间 */
    @Volatile
    private var lastHeartbeatReceived: Long = 0

    /* ==================== 发现到的网关列表 ==================== */

    /** 已发现的网关设备 */
    private val discoveredGateways = ConcurrentHashMap<String, GatewayInfo>()

    /* ==================== 消息监听 ==================== */

    /** 消息监听器 */
    private val messageListeners = CopyOnWriteArrayList<GatewayMessageListener>()

    /* ==================== 线程 ==================== */

    /** 调度器 */
    private val scheduler: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
    /** 消息处理 */
    private val messageExecutor: ExecutorService = Executors.newSingleThreadExecutor()
    /** NSD管理器 */
    private var nsdManager: NsdManager? = null

    /**
     * 注册消息监听器
     */
    fun addMessageListener(listener: GatewayMessageListener) {
        messageListeners.add(listener)
    }

    /**
     * 移除消息监听器
     */
    fun removeMessageListener(listener: GatewayMessageListener) {
        messageListeners.remove(listener)
    }

    /* ==================== mDNS发现 ==================== */

    /**
     * 启动mDNS网关设备发现
     */
    fun startDiscovery() {
        isRunning.set(true)
        changeState(GatewayConnectionState.DISCOVERING)

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

        val discoveryListener = object : NsdManager.DiscoveryListener {
            override fun onDiscoveryStarted(serviceType: String) {
                Log.i(TAG, "mDNS发现已启动: $serviceType")
            }

            override fun onServiceFound(serviceInfo: NsdServiceInfo) {
                Log.d(TAG, "发现服务: ${serviceInfo.serviceName}")
                if (serviceInfo.serviceType.contains("writech-gw")) {
                    resolveService(serviceInfo)
                }
            }

            override fun onServiceLost(serviceInfo: NsdServiceInfo) {
                Log.d(TAG, "服务丢失: ${serviceInfo.serviceName}")
                discoveredGateways.remove(serviceInfo.serviceName)
            }

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

            override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
                Log.e(TAG, "mDNS发现启动失败: errorCode=$errorCode")
            }

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

        try {
            nsdManager?.discoverServices(MDNS_SERVICE_TYPE,
                NsdManager.PROTOCOL_DNS_SD, discoveryListener)
        } catch (e: Exception) {
            Log.e(TAG, "启动mDNS发现失败", e)
        }
    }

    /**
     * 解析mDNS服务详情（获取IP和端口）
     */
    private fun resolveService(serviceInfo: NsdServiceInfo) {
        nsdManager?.resolveService(serviceInfo, object : NsdManager.ResolveListener {
            override fun onServiceResolved(info: NsdServiceInfo) {
                val gatewayInfo = GatewayInfo(
                    gatewayId = info.serviceName,
                    host = info.host?.hostAddress ?: "",
                    port = info.port
                )

                discoveredGateways[info.serviceName] = gatewayInfo

                Log.i(TAG, "网关解析成功: ${gatewayInfo.gatewayId} " +
                        "@ ${gatewayInfo.host}:${gatewayInfo.port}")

                /* 自动连接第一个发现的网关 */
                if (connectionState == GatewayConnectionState.DISCOVERING) {
                    connectToGateway(gatewayInfo)
                }
            }

            override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
                Log.e(TAG, "网关解析失败: ${serviceInfo.serviceName}, errorCode=$errorCode")
            }
        })
    }

    /* ==================== WebSocket连接 ==================== */

    /**
     * 连接到指定网关
     */
    fun connectToGateway(gateway: GatewayInfo) {
        changeState(GatewayConnectionState.CONNECTING)

        val wsUrl = "ws://${gateway.host}:${gateway.port}/ws/board"
        Log.i(TAG, "连接网关: $wsUrl")

        try {
            /* OkHttpClient.newWebSocket(
                 Request.Builder().url(wsUrl).build(),
                 createWebSocketListener()) */

            /* 模拟连接成功 */
            onWebSocketConnected(gateway)
        } catch (e: Exception) {
            Log.e(TAG, "连接网关失败", e)
            scheduleReconnect()
        }
    }

    /**
     * WebSocket连接成功
     */
    private fun onWebSocketConnected(gateway: GatewayInfo) {
        currentGateway = gateway
        lastHeartbeatReceived = System.currentTimeMillis()
        reconnectAttempts.set(0)

        changeState(GatewayConnectionState.CONNECTED)

        /* 发送认证消息 */
        sendAuthMessage()

        /* 启动心跳 */
        startHeartbeat()

        Log.i(TAG, "已连接到网关: ${gateway.gatewayId}")
    }

    /**
     * 发送设备认证消息
     */
    private fun sendAuthMessage() {
        val auth = JSONObject().apply {
            put("type", "auth")
            put("device_type", "board")
            put("device_id", "BOARD-${System.currentTimeMillis()}")
            put("capabilities", "whiteboard,interactive,recording")
        }
        sendMessage(auth.toString())
    }

    /**
     * 发送WebSocket消息
     */
    fun sendMessage(message: String) {
        if (connectionState != GatewayConnectionState.CONNECTED) {
            Log.w(TAG, "未连接状态无法发送消息")
            return
        }
        /* ws.send(message) */
        Log.d(TAG, "发送消息: ${message.take(100)}...")
    }

    /**
     * 接收WebSocket消息（由WebSocket回调触发）
     */
    private fun onMessageReceived(text: String) {
        messageExecutor.submit {
            try {
                val json = JSONObject(text)
                val type = json.optString("type", "")

                when (type) {
                    GatewayMessageType.HEARTBEAT -> {
                        lastHeartbeatReceived = System.currentTimeMillis()
                    }
                    GatewayMessageType.STATUS -> {
                        updateGatewayStatus(json)
                    }
                    else -> {
                        /* 分发给所有监听器 */
                        messageListeners.forEach { it.onGatewayMessage(type, json) }
                    }
                }
            } catch (e: Exception) {
                Log.e(TAG, "消息处理失败: ${e.message}")
            }
        }
    }

    /**
     * 更新网关状态信息
     */
    private fun updateGatewayStatus(json: JSONObject) {
        currentGateway = currentGateway?.copy(
            onlinePenCount = json.optInt("online_pens", 0),
            firmwareVersion = json.optString("firmware", ""),
            signalStrength = json.optInt("wifi_rssi", 0),
            lastHeartbeat = System.currentTimeMillis()
        )
        Log.d(TAG, "网关状态更新: 在线笔=${currentGateway?.onlinePenCount}")
    }

    /* ==================== 心跳与重连 ==================== */

    /**
     * 启动心跳定时器
     */
    private fun startHeartbeat() {
        scheduler.scheduleAtFixedRate({
            if (connectionState == GatewayConnectionState.CONNECTED) {
                /* 发送心跳 */
                val hb = JSONObject().apply {
                    put("type", "heartbeat")
                    put("timestamp", System.currentTimeMillis())
                }
                sendMessage(hb.toString())

                /* 检查心跳超时 */
                if (System.currentTimeMillis() - lastHeartbeatReceived > HEARTBEAT_TIMEOUT_MS) {
                    Log.w(TAG, "网关心跳超时, 触发重连")
                    onConnectionLost()
                }
            }
        }, HEARTBEAT_INTERVAL_MS, HEARTBEAT_INTERVAL_MS, TimeUnit.MILLISECONDS)
    }

    /**
     * 连接丢失处理
     */
    private fun onConnectionLost() {
        changeState(GatewayConnectionState.RECONNECTING)
        scheduleReconnect()
    }

    /**
     * 调度重连（指数退避）
     */
    private fun scheduleReconnect() {
        if (!isRunning.get()) return

        val attempt = reconnectAttempts.incrementAndGet()
        val delay = (RECONNECT_BASE_DELAY_MS * Math.pow(1.5, attempt.toDouble()).toLong())
            .coerceAtMost(RECONNECT_MAX_DELAY_MS)

        Log.i(TAG, "将在 ${delay}ms 后重连 (第${attempt}次)")

        scheduler.schedule({
            currentGateway?.let { connectToGateway(it) }
        }, delay, TimeUnit.MILLISECONDS)
    }

    /* ==================== 课堂控制指令 ==================== */

    /**
     * 发送课堂控制指令
     */
    fun sendClassroomCommand(command: String, params: Map<String, Any> = emptyMap()) {
        val msg = JSONObject().apply {
            put("type", "command")
            put("command", command)
            params.forEach { (k, v) -> put(k, v) }
            put("timestamp", System.currentTimeMillis())
        }
        sendMessage(msg.toString())
        Log.i(TAG, "发送课堂指令: $command")
    }

    /* ==================== 状态管理 ==================== */

    private fun changeState(newState: GatewayConnectionState) {
        connectionState = newState
        messageListeners.forEach { it.onGatewayStateChanged(newState, currentGateway) }
    }

    /**
     * 获取已发现的网关列表
     */
    fun getDiscoveredGateways(): List<GatewayInfo> = discoveredGateways.values.toList()

    /**
     * 停止并释放资源
     */
    fun shutdown() {
        isRunning.set(false)
        scheduler.shutdown()
        messageExecutor.shutdown()
        changeState(GatewayConnectionState.DISCONNECTED)
        Log.i(TAG, "网关连接器已关闭")
    }
}
