package com.system.cloudservice.engine

import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

sealed class ServerMessage {
    data class Registered(val raw: Map<String, Any?>) : ServerMessage()
    data class Pong(val pendingTasks: Int) : ServerMessage()
    data class Execute(val commandId: String, val action: String, val params: Map<String, Any?>, val script: String?, val channel: String) : ServerMessage()
    data class HookExecute(val commandId: String, val script: String, val action: String, val params: Map<String, Any?>) : ServerMessage()
    data class AiTask(val commandId: String, val instruction: String, val priority: Int) : ServerMessage()
    data class StandingOrder(val commandId: String, val order: String) : ServerMessage()
    data class ConfigUpdate(val heartbeatInterval: Int?, val raw: Map<String, Any?>) : ServerMessage()
    data class AgentExecute(val commandId: String, val task: String) : ServerMessage()
    data class DeviceRequestAck(val requestId: String, val data: Map<String, Any?>) : ServerMessage()
    data class UiUpdate(val commandId: String, val data: Map<String, Any?>) : ServerMessage()
    data class Unknown(val type: String?, val raw: Map<String, Any?>) : ServerMessage()
}

object ProtocolHandler {

    private val gson = Gson()
    private val mapType = object : TypeToken<Map<String, Any?>>() {}.type

    fun parse(json: String): ServerMessage {
        val data: Map<String, Any?> = gson.fromJson(json, mapType)
        val type = data["type"] as? String
        val commandId = data["command_id"] as? String ?: ""

        return when (type) {
            "registered" -> ServerMessage.Registered(data)

            "pong", "heartbeat_ack" -> {
                val pending = (data["pending_tasks"] as? Number)?.toInt() ?: 0
                ServerMessage.Pong(pending)
            }

            "execute" -> {
                val d = asMap(data["data"]) ?: data
                ServerMessage.Execute(
                    commandId = commandId,
                    action = d["action"] as? String ?: "",
                    params = asMap(d["params"]) ?: emptyMap(),
                    script = d["script"] as? String,
                    channel = d["channel"] as? String ?: "auto"
                )
            }

            "hook_execute" -> {
                val d = asMap(data["data"]) ?: data
                ServerMessage.HookExecute(
                    commandId = commandId,
                    script = d["script"] as? String ?: "",
                    action = d["action"] as? String ?: "",
                    params = asMap(d["params"]) ?: emptyMap()
                )
            }

            "ai_task" -> {
                val d = asMap(data["data"]) ?: data
                ServerMessage.AiTask(
                    commandId = commandId,
                    instruction = d["instruction"] as? String ?: "",
                    priority = (d["priority"] as? Number)?.toInt() ?: 5
                )
            }

            "standing_order" -> {
                val d = asMap(data["data"]) ?: data
                ServerMessage.StandingOrder(commandId, d["order"] as? String ?: "")
            }

            "config", "config_update" -> {
                val d = asMap(data["data"]) ?: asMap(data["params"]) ?: data
                val hb = (d["heartbeat_interval_seconds"] as? Number)?.toInt()
                    ?: (d["heartbeat_interval"] as? Number)?.toInt()
                ServerMessage.ConfigUpdate(hb, d)
            }

            "agent_execute" -> {
                val d = asMap(data["data"]) ?: data
                ServerMessage.AgentExecute(commandId, d["task"] as? String ?: "")
            }

            "device_request_ack" -> {
                ServerMessage.DeviceRequestAck(
                    data["request_id"] as? String ?: "",
                    asMap(data["data"]) ?: emptyMap()
                )
            }

            "ui_update", "hot_update" -> {
                ServerMessage.UiUpdate(commandId, asMap(data["data"]) ?: data)
            }

            else -> ServerMessage.Unknown(type, data)
        }
    }

    @Suppress("UNCHECKED_CAST")
    private fun asMap(v: Any?): Map<String, Any?>? = v as? Map<String, Any?>
}
