package com.example.m20_gamepad.ui

import android.app.Application
import android.content.Context
import android.net.wifi.WifiManager
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.m20_gamepad.data.AppSettings
import com.example.m20_gamepad.data.SettingsRepository
import com.example.m20_gamepad.network.ProtocolClient
import com.example.m20_gamepad.network.models.BatteryStatus
import com.example.m20_gamepad.network.models.ControlCommands
import com.example.m20_gamepad.network.models.DeviceTemperature
import com.example.m20_gamepad.network.models.ErrorInfo
import com.example.m20_gamepad.network.models.LedStatus
import com.example.m20_gamepad.network.models.MotionStatus
import com.example.m20_gamepad.network.models.StatusReport
import com.example.m20_gamepad.service.JoystickController
import com.example.m20_gamepad.service.MotionTransitionResult
import com.example.m20_gamepad.service.PingMonitor
import com.example.m20_gamepad.service.RobotConnection
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

/**
 * 主界面 ViewModel。管理 ProtocolClient 生命周期、状态收集、轴指令 20Hz 发送。
 *
 * 连接参数从 [SettingsRepository] 读取，不再使用硬编码默认值。
 * 设置变更时若已连接则断开，下次连接使用新参数。
 *
 * 运动指令经 [RobotConnection] 状态机校验：步态切换/轴指令仅 RL 控制下放行，
 * 运动状态转换按 proto.md 2.3 正向流程校验。
 *
 * @param repository 应用级设置仓库
 */
class MainViewModel(
    private val repository: SettingsRepository,
    private val application: Application
) : ViewModel() {

    companion object {
        private const val AXIS_SEND_INTERVAL_MS = 50L // 20 Hz
    }

    private var client: ProtocolClient? = null
    private val robot = RobotConnection()

    val connectionState: StateFlow<ProtocolClient.State> = robot.connectionState

    /** 当前运动状态（来自状态上报，0=空闲 1=站立 17=RL控制 ...）。 */
    val motionState: StateFlow<Int> = robot.motionState

    private val _latestStatus = MutableStateFlow<StatusReport?>(null)
    val latestStatus: StateFlow<StatusReport?> = _latestStatus.asStateFlow()

    /** 状态面板用：分项最新值（各上报频率不同，分别缓存最近一次）。 */
    private val _errorList = MutableStateFlow<List<ErrorInfo>?>(null)
    val errorList: StateFlow<List<ErrorInfo>?> = _errorList.asStateFlow()

    private val _motionStatus = MutableStateFlow<MotionStatus?>(null)
    val motionStatus: StateFlow<MotionStatus?> = _motionStatus.asStateFlow()

    private val _deviceTemperature = MutableStateFlow<DeviceTemperature?>(null)
    val deviceTemperature: StateFlow<DeviceTemperature?> = _deviceTemperature.asStateFlow()

    private val _batteryStatus = MutableStateFlow<BatteryStatus?>(null)
    val batteryStatus: StateFlow<BatteryStatus?> = _batteryStatus.asStateFlow()

    private val _ledStatus = MutableStateFlow<LedStatus?>(null)
    val ledStatus: StateFlow<LedStatus?> = _ledStatus.asStateFlow()

    private val _lastUpdate = MutableStateFlow<String?>(null)
    val lastUpdate: StateFlow<String?> = _lastUpdate.asStateFlow()

    /** 最近一次指令的校验反馈（供 UI 提示）。 */
    private val _actionFeedback = MutableStateFlow<String?>(null)
    val actionFeedback: StateFlow<String?> = _actionFeedback.asStateFlow()

    /** ICMP 延迟（毫秒），null 表示无数据或未连接。 */
    private val _pingLatencyMs = MutableStateFlow<Long?>(null)
    val pingLatencyMs: StateFlow<Long?> = _pingLatencyMs.asStateFlow()

    private var pingMonitor: PingMonitor? = null

    /** WiFi 信号强度级别（0-5 格），0=无WiFi/无信号。 */
    private val _wifiSignalLevel = MutableStateFlow(0)
    val wifiSignalLevel: StateFlow<Int> = _wifiSignalLevel.asStateFlow()

    private var wifiJob: Job? = null

    /** 当前设置快照（主界面用于驱动视频播放器地址/编码器） */
    val settings: StateFlow<AppSettings> = repository.settings.stateIn(
        scope = viewModelScope,
        started = SharingStarted.Eagerly,
        initialValue = AppSettings()
    )

    // 摇杆状态（UI 线程更新，轴指令协程读取）
    @Volatile private var leftAngle = 0.0
    @Volatile private var leftPower = 0.0
    @Volatile private var rightAngle = 0.0
    @Volatile private var rightPower = 0.0

    private var axisJob: Job? = null
    private var statusJob: Job? = null
    private var settingsWatchJob: Job? = null

    val isConnected: Boolean get() = robot.isConnected

    init {
        // 启动 ICMP 延迟监测（独立于连接生命周期）
        restartPingMonitor(settings.value.robotHost)
        // 设置中 host 变更时重启 ping
        viewModelScope.launch {
            settings
                .map { it.robotHost }
                .distinctUntilChanged()
                .collect { host -> restartPingMonitor(host) }
        }
        // 启动 WiFi 信号强度监测（独立于连接生命周期）
        startWifiMonitoring()
        // 设置变更时断开当前连接，下次 connect 使用新参数
        settingsWatchJob = viewModelScope.launch {
            settings
                .map { it.robotHost to it.robotPort }
                .distinctUntilChanged()
                .collect { if (client != null) disconnect() }
        }
    }

    /** 启动 WiFi 信号强度周期性监测。 */
    private fun startWifiMonitoring() {
        wifiJob?.cancel()
        wifiJob = viewModelScope.launch {
            val wifiManager = application.getSystemService(Context.WIFI_SERVICE) as? WifiManager
            if (wifiManager == null) {
                _wifiSignalLevel.value = 0
                return@launch
            }
            while (isActive) {
                val info = wifiManager.connectionInfo
                val rssi = info?.rssi ?: -127
                _wifiSignalLevel.value = if (rssi == -127 || info == null) {
                    0
                } else {
                    when {
                        rssi >= -50 -> 5
                        rssi >= -60 -> 4
                        rssi >= -70 -> 3
                        rssi >= -80 -> 2
                        rssi >= -90 -> 1
                        else -> 0
                    }
                }
                delay(3000L)
            }
        }
    }

    /** 重启 PingMonitor（目标 host 变更时调用）。 */
    private fun restartPingMonitor(host: String) {
        pingMonitor?.stop()
        pingMonitor = PingMonitor(host, scope = viewModelScope).also { it.start() }
        viewModelScope.launch {
            pingMonitor?.latencyMs?.collect { _pingLatencyMs.value = it }
        }
    }

    /**
     * 建立连接并启动轴指令循环。参数取自当前设置。
     *
     * 已连接时为幂等 no-op；处于断线/错误状态时先清理旧 client 再重连，
     * 避免旧 client 非空导致无法从 TIMEOUT/ERROR 恢复。
     */
    fun connect() {
        if (client != null) {
            if (robot.isConnected) return
            // 断线/错误：先清理旧连接再重连
            disconnect()
        }
        val s = settings.value

        val c = ProtocolClient(s.robotHost, s.robotPort, viewModelScope)
        client = c

        statusJob = viewModelScope.launch {
            c.state.collect { state ->
                // 经状态机校验后写入；非法跳转忽略（保留旧状态）
                robot.updateConnectionState(state)
            }
        }
        viewModelScope.launch {
            c.onStatusReport.collect { report -> handleStatusReport(report) }
        }

        c.connect()
        startAxisLoop()
    }

    /**
     * 断开连接。
     */
    fun disconnect() {
        axisJob?.cancel()
        axisJob = null
        statusJob?.cancel()
        statusJob = null
        client?.disconnect()
        client = null
        robot.reset()
        _latestStatus.value = null
        _errorList.value = null
        _motionStatus.value = null
        _deviceTemperature.value = null
        _batteryStatus.value = null
        _ledStatus.value = null
        _lastUpdate.value = null
    }

    /** 状态上报分发：更新机器人运动状态机 + 各分项缓存。 */
    private fun handleStatusReport(report: StatusReport) {
        _latestStatus.value = report
        _lastUpdate.value = report.time
        robot.updateFromReport(report)
        report.errorList?.let { _errorList.value = it }
        report.motionStatus?.let { _motionStatus.value = it }
        report.deviceTemperature?.let { _deviceTemperature.value = it }
        report.batteryStatus?.let { _batteryStatus.value = it }
        report.led?.let { _ledStatus.value = it }
        // 通用响应错误提示
        report.errorCode?.let { code ->
            if (code != 0) {
                _actionFeedback.value = "指令失败: ${report.errorMessage ?: code.toString()}"
            }
        }
    }

    // ---- 摇杆输入 ----

    fun updateLeftStick(angle: Double, power: Double) {
        leftAngle = angle
        leftPower = power
    }

    fun updateRightStick(angle: Double, power: Double) {
        rightAngle = angle
        rightPower = power
    }

    // ---- 控制指令（经状态机校验） ----

    fun sendMotionControl(motionParam: Int) {
        when (robot.requestMotionTransition(motionParam)) {
            MotionTransitionResult.ACCEPTED ->
                client?.sendCommandBlocking(ControlCommands.motionControl(motionParam))
            MotionTransitionResult.REJECTED_NOT_CONNECTED ->
                _actionFeedback.value = "未连接，无法切换运动状态"
            MotionTransitionResult.REJECTED_INVALID_TRANSITION ->
                _actionFeedback.value = "当前状态不允许切换到该运动状态"
            MotionTransitionResult.REJECTED_ALREADY_IN_STATE ->
                _actionFeedback.value = "已处于该运动状态"
        }
    }

    fun sendSwitchGait(gaitParam: Int) {
        if (!robot.canSwitchGait) {
            _actionFeedback.value = "需先进入 RL 控制状态才能切换步态"
            return
        }
        client?.sendCommandBlocking(ControlCommands.switchGait(gaitParam))
    }

    fun sendSwitchMode(mode: Int) {
        client?.sendCommandBlocking(ControlCommands.switchMode(mode))
    }

    fun sendLightControl(front: Int, back: Int) {
        client?.sendCommandBlocking(ControlCommands.lightControl(front, back))
    }

    fun sendChargeControl(charge: Int) {
        client?.sendCommandBlocking(ControlCommands.chargeControl(charge))
    }

    fun sendSleepSettings(sleep: Boolean, auto: Boolean = false, timeMinutes: Int = 5) {
        client?.sendCommandBlocking(
            ControlCommands.sleepSettings(sleep, auto, timeMinutes)
        )
    }

    /** 清除指令反馈。 */
    fun clearActionFeedback() {
        _actionFeedback.value = null
    }

    // ---- 内部 ----

    /**
     * 轴指令发送循环：20 Hz 发送双摇杆合并的轴指令。
     * 仅在 RL 控制状态下发送摇杆指令；否则发零速度保持连接（避免残留运动）。
     */
    private fun startAxisLoop() {
        axisJob = viewModelScope.launch {
            while (isActive) {
                val c = client
                if (c != null && c.isConnected) {
                    val cmd = if (robot.canSendAxisCommand) {
                        JoystickController.dualStickToAxisCommand(
                            leftAngle, leftPower,
                            rightAngle, rightPower
                        )
                    } else {
                        // 非 RL 控制：发零速度
                        ControlCommands.axisCommand()
                    }
                    c.sendCommand(cmd)
                }
                delay(AXIS_SEND_INTERVAL_MS)
            }
        }
    }

    override fun onCleared() {
        disconnect()
        wifiJob?.cancel()
        pingMonitor?.stop()
        pingMonitor = null
        settingsWatchJob?.cancel()
        super.onCleared()
    }
}