package com.example.m20_gamepad.network.models

import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.boolean
import kotlinx.serialization.json.double
import kotlinx.serialization.json.int
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive

/**
 * 状态上报解析结果。所有字段可为 null，表示该次上报中不存在。
 */
data class StatusReport(
    val type: Int,
    val command: Int,
    val time: String,
    // 通用响应
    val errorCode: Int? = null,
    val errorMessage: String? = null,
    // 基础状态 (Cmd=6)
    val basicStatus: BasicStatus? = null,
    // 运控状态 (Cmd=4)
    val motionStatus: MotionStatus? = null,
    val motorStatus: MotorStatus? = null,
    // 设备状态 (Cmd=5)
    val batteryList: List<BatteryInfo>? = null,
    val batteryStatus: BatteryStatus? = null,
    val deviceTemperature: DeviceTemperature? = null,
    val led: LedStatus? = null,
    val gps: GpsInfo? = null,
    val devEnable: DevEnable? = null,
    val cpu: CpuInfo? = null,
    // 异常状态 (Cmd=3)
    val errorList: List<ErrorInfo>? = null
)

data class BasicStatus(
    val motionState: Int,
    val gait: Int,
    val charge: Int,
    val hes: Int,
    val controlUsageMode: Int,
    val direction: Int,
    val ooa: Int,
    val powerManagement: Int,
    val sleep: Int,
    val version: String
)

data class MotionStatus(
    val roll: Double,
    val pitch: Double,
    val yaw: Double,
    val omegaZ: Double,
    val linearX: Double,
    val linearY: Double,
    val height: Double,
    val payload: Double,
    val remainMile: Double
)

data class MotorStatus(
    val joint: List<Double>,
    val leftFrontHipX: Double,
    val leftFrontHipY: Double,
    val leftFrontKnee: Double,
    val leftFrontWheel: Double,
    val rightFrontHipX: Double,
    val rightFrontHipY: Double,
    val rightFrontKnee: Double,
    val rightFrontWheel: Double,
    val leftBackHipX: Double,
    val leftBackHipY: Double,
    val leftBackKnee: Double,
    val leftBackWheel: Double,
    val rightBackHipX: Double,
    val rightBackHipY: Double,
    val rightBackKnee: Double,
    val rightBackWheel: Double
)

data class BatteryInfo(
    val voltage: Double,
    val batteryLevel: Double,
    val batteryTemperature: Double,
    val charge: Boolean,
    val serial: String
)

data class BatteryStatus(
    val voltageLeft: Double,
    val voltageRight: Double,
    val batteryLevelLeft: Double,
    val batteryLevelRight: Double,
    val batteryTemperatureLeft: Double,
    val batteryTemperatureRight: Double,
    val chargeLeft: Boolean,
    val chargeRight: Boolean
)

data class DeviceTemperature(
    val motor: List<Double>,
    val driver: List<Double>
)

data class LedStatus(
    val front: Int,
    val back: Int
)

data class GpsInfo(
    val latitude: Double,
    val longitude: Double,
    val speed: Double,
    val course: Double,
    val fixQuality: Int,
    val numSatellites: Int,
    val altitude: Double,
    val hdop: Double,
    val vdop: Double,
    val pdop: Double,
    val visibleSatellites: Int
)

data class DevEnable(
    val fanSpeed: Int,
    val loadPower: Int,
    val ledHost: Int,
    val ledExt: Int,
    val fp: Int,
    val lidarFront: Int,
    val lidarBack: Int,
    val gps: Int,
    val videoFront: Int,
    val videoBack: Int
)

data class CpuInfo(
    val aosTemperature: Double,
    val aosFrequencyInt: Double,
    val aosFrequencyApp: Double,
    val nosTemperature: Double,
    val nosFrequencyInt: Double,
    val nosFrequencyApp: Double,
    val gosTemperature: Double,
    val gosFrequencyInt: Double,
    val gosFrequencyApp: Double
)

data class ErrorInfo(
    val errorCode: Int,
    val component: Int
)

/**
 * 从 JSON 解析 StatusReport。
 * 输入为完整的 JSON 字符串（包含 PatrolDevice 外层）。
 */
fun parseStatusReport(json: String): StatusReport? {
    return try {
        val root = kotlinx.serialization.json.Json.parseToJsonElement(json).jsonObject
        val patrolDevice = root["PatrolDevice"]?.jsonObject ?: return null
        val type = patrolDevice["Type"]?.jsonPrimitive?.int ?: return null
        val command = patrolDevice["Command"]?.jsonPrimitive?.int ?: return null
        val time = patrolDevice["Time"]?.jsonPrimitive?.content.orEmpty()
        val items = patrolDevice["Items"]?.jsonObject ?: return null

        StatusReport(
            type = type,
            command = command,
            time = time,
            errorCode = items["ErrorCode"]?.jsonPrimitive?.int,
            errorMessage = items["ErrorMessage"]?.jsonPrimitive?.content,
            basicStatus = parseBasicStatus(items["BasicStatus"]?.jsonObject),
            motionStatus = parseMotionStatus(items["MotionStatus"]?.jsonObject),
            motorStatus = parseMotorStatus(items["MotorStatus"]?.jsonObject),
            batteryList = parseBatteryList(items["BatteryList"]?.jsonArray),
            batteryStatus = parseBatteryStatus(items["BatteryStatus"]?.jsonObject),
            deviceTemperature = parseDeviceTemperature(items["DeviceTemperature"]?.jsonObject),
            led = parseLed(items["Led"]?.jsonObject),
            gps = parseGps(items["GPS"]?.jsonObject),
            devEnable = parseDevEnable(items["DevEnable"]?.jsonObject),
            cpu = parseCpu(items["CPU"]?.jsonObject),
            errorList = parseErrorList(items["ErrorList"]?.jsonArray)
        )
    } catch (_: Exception) {
        null
    }
}

private fun parseBasicStatus(obj: JsonObject?): BasicStatus? {
    if (obj == null) return null
    return BasicStatus(
        motionState = obj["MotionState"]?.jsonPrimitive?.int ?: return null,
        gait = obj["Gait"]?.jsonPrimitive?.int ?: 0,
        charge = obj["Charge"]?.jsonPrimitive?.int ?: 0,
        hes = obj["HES"]?.jsonPrimitive?.int ?: 0,
        controlUsageMode = obj["ControlUsageMode"]?.jsonPrimitive?.int ?: 0,
        direction = obj["Direction"]?.jsonPrimitive?.int ?: 0,
        ooa = obj["OOA"]?.jsonPrimitive?.int ?: 0,
        powerManagement = obj["PowerManagement"]?.jsonPrimitive?.int ?: 0,
        sleep = obj["Sleep"]?.jsonPrimitive?.int ?: 0,
        version = obj["Version"]?.jsonPrimitive?.content.orEmpty()
    )
}

private fun parseMotionStatus(obj: JsonObject?): MotionStatus? {
    if (obj == null) return null
    return MotionStatus(
        roll = obj["Roll"]?.jsonPrimitive?.double ?: 0.0,
        pitch = obj["Pitch"]?.jsonPrimitive?.double ?: 0.0,
        yaw = obj["Yaw"]?.jsonPrimitive?.double ?: 0.0,
        omegaZ = obj["OmegaZ"]?.jsonPrimitive?.double ?: 0.0,
        linearX = obj["LinearX"]?.jsonPrimitive?.double ?: 0.0,
        linearY = obj["LinearY"]?.jsonPrimitive?.double ?: 0.0,
        height = obj["Height"]?.jsonPrimitive?.double ?: 0.0,
        payload = obj["Payload"]?.jsonPrimitive?.double ?: 0.0,
        remainMile = obj["RemainMile"]?.jsonPrimitive?.double ?: 0.0
    )
}

private fun parseMotorStatus(obj: JsonObject?): MotorStatus? {
    if (obj == null) return null
    fun getDouble(key: String) = obj[key]?.jsonPrimitive?.double ?: 0.0
    fun getList(key: String) = obj[key]?.jsonArray?.map { it.jsonPrimitive.double } ?: emptyList()
    return MotorStatus(
        joint = getList("Joint"),
        leftFrontHipX = getDouble("LeftFrontHipX"),
        leftFrontHipY = getDouble("LeftFrontHipY"),
        leftFrontKnee = getDouble("LeftFrontKnee"),
        leftFrontWheel = getDouble("LeftFrontWheel"),
        rightFrontHipX = getDouble("RightFrontHipX"),
        rightFrontHipY = getDouble("RightFrontHipY"),
        rightFrontKnee = getDouble("RightFrontKnee"),
        rightFrontWheel = getDouble("RightFrontWheel"),
        leftBackHipX = getDouble("LeftBackHipX"),
        leftBackHipY = getDouble("LeftBackHipY"),
        leftBackKnee = getDouble("LeftBackKnee"),
        leftBackWheel = getDouble("LeftBackWheel"),
        rightBackHipX = getDouble("RightBackHipX"),
        rightBackHipY = getDouble("RightBackHipY"),
        rightBackKnee = getDouble("RightBackKnee"),
        rightBackWheel = getDouble("RightBackWheel")
    )
}

private fun parseBatteryList(arr: JsonElement?): List<BatteryInfo>? {
    if (arr == null) return null
    return arr.jsonArray.map { elem ->
        val obj = elem.jsonObject
        BatteryInfo(
            voltage = obj["Voltage"]?.jsonPrimitive?.double ?: 0.0,
            batteryLevel = obj["BatteryLevel"]?.jsonPrimitive?.double ?: 0.0,
            batteryTemperature = obj["battery_temperature"]?.jsonPrimitive?.double ?: 0.0,
            charge = obj["charge"]?.jsonPrimitive?.boolean ?: false,
            serial = obj["serial"]?.jsonPrimitive?.content.orEmpty()
        )
    }
}

private fun parseBatteryStatus(obj: JsonObject?): BatteryStatus? {
    if (obj == null) return null
    return BatteryStatus(
        voltageLeft = obj["VoltageLeft"]?.jsonPrimitive?.double ?: 0.0,
        voltageRight = obj["VoltageRight"]?.jsonPrimitive?.double ?: 0.0,
        batteryLevelLeft = obj["BatteryLevelLeft"]?.jsonPrimitive?.double ?: 0.0,
        batteryLevelRight = obj["BatteryLevelRight"]?.jsonPrimitive?.double ?: 0.0,
        batteryTemperatureLeft = obj["battery_temperatureLeft"]?.jsonPrimitive?.double ?: 0.0,
        batteryTemperatureRight = obj["battery_temperatureRight"]?.jsonPrimitive?.double ?: 0.0,
        chargeLeft = obj["chargeLeft"]?.jsonPrimitive?.boolean ?: false,
        chargeRight = obj["chargeRight"]?.jsonPrimitive?.boolean ?: false
    )
}

private fun parseDeviceTemperature(obj: JsonObject?): DeviceTemperature? {
    if (obj == null) return null
    fun getList(key: String) = obj[key]?.jsonArray?.map { it.jsonPrimitive.double } ?: emptyList()
    return DeviceTemperature(
        motor = getList("Motor"),
        driver = getList("Driver")
    )
}

private fun parseLed(obj: JsonObject?): LedStatus? {
    if (obj == null) return null
    val fill = obj["Fill"]?.jsonObject ?: return null
    return LedStatus(
        front = fill["Front"]?.jsonPrimitive?.int ?: 0,
        back = fill["Back"]?.jsonPrimitive?.int ?: 0
    )
}

private fun parseGps(obj: JsonObject?): GpsInfo? {
    if (obj == null) return null
    return GpsInfo(
        latitude = obj["Latitude"]?.jsonPrimitive?.double ?: 0.0,
        longitude = obj["Longitude"]?.jsonPrimitive?.double ?: 0.0,
        speed = obj["Speed"]?.jsonPrimitive?.double ?: 0.0,
        course = obj["Course"]?.jsonPrimitive?.double ?: 0.0,
        fixQuality = obj["FixQuality"]?.jsonPrimitive?.int ?: 0,
        numSatellites = obj["NumSatellites"]?.jsonPrimitive?.int ?: 0,
        altitude = obj["Altitude"]?.jsonPrimitive?.double ?: 0.0,
        hdop = obj["HDOP"]?.jsonPrimitive?.double ?: 0.0,
        vdop = obj["VDOP"]?.jsonPrimitive?.double ?: 0.0,
        pdop = obj["PDOP"]?.jsonPrimitive?.double ?: 0.0,
        visibleSatellites = obj["VisibleSatellites"]?.jsonPrimitive?.int ?: 0
    )
}

private fun parseDevEnable(obj: JsonObject?): DevEnable? {
    if (obj == null) return null
    val lidar = obj["Lidar"]?.jsonObject
    val video = obj["Video"]?.jsonObject
    return DevEnable(
        fanSpeed = obj["FanSpeed"]?.jsonPrimitive?.int ?: 0,
        loadPower = obj["LoadPower"]?.jsonPrimitive?.int ?: 0,
        ledHost = obj["LedHost"]?.jsonPrimitive?.int ?: 0,
        ledExt = obj["LedExt"]?.jsonPrimitive?.int ?: 0,
        fp = obj["FP"]?.jsonPrimitive?.int ?: 0,
        lidarFront = lidar?.get("Front")?.jsonPrimitive?.int ?: 0,
        lidarBack = lidar?.get("Back")?.jsonPrimitive?.int ?: 0,
        gps = obj["GPS"]?.jsonPrimitive?.int ?: 0,
        videoFront = video?.get("Front")?.jsonPrimitive?.int ?: 0,
        videoBack = video?.get("Back")?.jsonPrimitive?.int ?: 0
    )
}

private fun parseCpu(obj: JsonObject?): CpuInfo? {
    if (obj == null) return null
    fun getSub(key: String) = obj[key]?.jsonObject
    fun getDouble(sub: JsonObject?, field: String) = sub?.get(field)?.jsonPrimitive?.double ?: 0.0
    val aos = getSub("AOS")
    val nos = getSub("NOS")
    val gos = getSub("GOS")
    return CpuInfo(
        aosTemperature = getDouble(aos, "Temperature"),
        aosFrequencyInt = getDouble(aos, "FrequencyInt"),
        aosFrequencyApp = getDouble(aos, "FrequencyApp"),
        nosTemperature = getDouble(nos, "Temperature"),
        nosFrequencyInt = getDouble(nos, "FrequencyInt"),
        nosFrequencyApp = getDouble(nos, "FrequencyApp"),
        gosTemperature = getDouble(gos, "Temperature"),
        gosFrequencyInt = getDouble(gos, "FrequencyInt"),
        gosFrequencyApp = getDouble(gos, "FrequencyApp")
    )
}

private fun parseErrorList(arr: JsonElement?): List<ErrorInfo>? {
    if (arr == null) return null
    return arr.jsonArray.map { elem ->
        val obj = elem.jsonObject
        ErrorInfo(
            errorCode = obj["errorCode"]?.jsonPrimitive?.int ?: 0,
            component = obj["component"]?.jsonPrimitive?.int ?: 0
        )
    }
}