package com.ruoyi.websocket.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.mqtt.constant.MqttTopicConstants;
import com.ruoyi.mqtt.util.MqttTopicUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * WebSocket消息推送服务
 * 将MQTT接收到的机器人数据实时推送给WebSocket客户端
 */
@Service
public class WebSocketPushService {

    private static final Logger log = LoggerFactory.getLogger(WebSocketPushService.class);

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    /**
     * 推送机器人位姿数据到WebSocket
     * @param deviceId 设备ID
     * @param payload MQTT消息体
     */
    public void pushRobotPose(String deviceId, String payload) {
        try {
            JSONObject json = JSON.parseObject(payload);
            JSONArray argsArray = json.getJSONArray("args");
            if (argsArray != null && !argsArray.isEmpty()) {
                JSONObject poseData = argsArray.getJSONObject(0);
                JSONObject pose = poseData.getJSONObject("pose");
                JSONObject vel = poseData.getJSONObject("vel");
                JSONObject rtk = poseData.getJSONObject("rtk");
                
                JSONObject pushData = new JSONObject();
                pushData.put("deviceId", deviceId);
                pushData.put("type", "pose");
                pushData.put("timestamp", System.currentTimeMillis());
                
                JSONObject data = new JSONObject();
                if (pose != null) {
                    data.put("xyz", pose.getJSONArray("xyz"));
                    data.put("rpy", pose.getJSONArray("rpy"));
                    data.put("heading", pose.getDouble("heading"));
                }
                if (vel != null) {
                    data.put("velocity", vel.getDouble("enu"));
                    data.put("heading", vel.getDouble("heading"));
                }
                data.put("confidence", poseData.getDouble("score"));
                data.put("runState", poseData.getInteger("runState"));
                data.put("odometer", poseData.getDouble("odometer"));
                data.put("replan", poseData.getDouble("replan"));

                if (rtk != null) {
                    JSONObject rtkInfo = new JSONObject();
                    rtkInfo.put("star", rtk.getInteger("star"));
                    rtkInfo.put("status", rtk.getInteger("status"));
                    data.put("rtk", rtkInfo);
                }
                
                pushData.put("data", data);
                
                // 推送到设备专属频道
                messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/pose", pushData);
                // 也推送到通用频道
                messagingTemplate.convertAndSend("/topic/robot/all/pose", pushData);
            }
        } catch (Exception e) {
            log.error("推送机器人位姿数据失败", e);
        }
    }

    /**
     * 推送任务实时信息
     * @param deviceId 设备ID
     * @param payload MQTT消息体
     */
    public void pushTaskRealtimeInfo(String deviceId, String payload) {
        try {
            JSONObject json = JSON.parseObject(payload);
            JSONArray argsArray = json.getJSONArray("args");
            if (argsArray != null && !argsArray.isEmpty()) {
                JSONObject taskInfo = argsArray.getJSONObject(0);
                
                JSONObject pushData = new JSONObject();
                pushData.put("deviceId", deviceId);
                pushData.put("type", "task_realtime");
                pushData.put("timestamp", System.currentTimeMillis());
                pushData.put("data", taskInfo);
                
                messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/task", pushData);
            }
        } catch (Exception e) {
            log.error("推送任务实时信息失败", e);
        }
    }

    /**
     * 推送轨迹数据
     * @param deviceId 设备ID
     * @param shortTopic 主题类型（trajectory 或 trajectory/2d/compact）
     * @param payload MQTT消息体
     */
    public void pushTrajectory(String deviceId, String shortTopic, String payload) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("deviceId", deviceId);
            pushData.put("type", "trajectory");
            pushData.put("subType", shortTopic);
            pushData.put("timestamp", System.currentTimeMillis());
            pushData.put("data", payload);
            
            messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/trajectory", pushData);
        } catch (Exception e) {
            log.error("推送轨迹数据失败", e);
        }
    }

    /**
     * 推送到达事件
     * @param deviceId 设备ID
     * @param payload MQTT消息体
     */
    public void pushArriveEvent(String deviceId, String payload) {
        try {
            JSONObject json = JSON.parseObject(payload);
            JSONArray argsArray = json.getJSONArray("args");
            if (argsArray != null && !argsArray.isEmpty()) {
                JSONObject arriveInfo = argsArray.getJSONObject(0);
                
                JSONObject pushData = new JSONObject();
                pushData.put("deviceId", deviceId);
                pushData.put("type", "arrive");
                pushData.put("timestamp", System.currentTimeMillis());
                pushData.put("data", arriveInfo);
                
                messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/event", pushData);
            }
        } catch (Exception e) {
            log.error("推送到达事件失败", e);
        }
    }

    /**
     * 推送地图列表响应
     * @param deviceId 设备ID
     * @param payload MQTT消息体
     */
    public void pushMapListResponse(String deviceId, String payload) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("deviceId", deviceId);
            pushData.put("type", "map_list");
            pushData.put("timestamp", System.currentTimeMillis());
            pushData.put("data", payload);
            
            messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/map", pushData);
        } catch (Exception e) {
            log.error("推送地图列表响应失败", e);
        }
    }

    /**
     * 推送当前地图
     * @param deviceId 设备ID
     * @param payload MQTT消息体
     */
    public void pushCurrentMap(String deviceId, String payload) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("deviceId", deviceId);
            pushData.put("type", "current_map");
            pushData.put("timestamp", System.currentTimeMillis());
            pushData.put("data", payload);
            
            messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/map", pushData);
        } catch (Exception e) {
            log.error("推送当前地图失败", e);
        }
    }

    /**
     * 推送导航操作响应
     * @param deviceId 设备ID
     * @param shortTopic 操作类型
     * @param payload MQTT消息体
     */
    public void pushNavigationReply(String deviceId, String shortTopic, String payload) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("deviceId", deviceId);
            pushData.put("type", "navigation_reply");
            pushData.put("action", shortTopic);
            pushData.put("timestamp", System.currentTimeMillis());
            pushData.put("data", payload);
            
            messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/navigation", pushData);
        } catch (Exception e) {
            log.error("推送导航响应失败", e);
        }
    }

    /**
     * 推送任务控制响应
     * @param deviceId 设备ID
     * @param shortTopic 操作类型
     * @param payload MQTT消息体
     */
    public void pushTaskProcedureReply(String deviceId, String shortTopic, String payload) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("deviceId", deviceId);
            pushData.put("type", "task_procedure_reply");
            pushData.put("action", shortTopic);
            pushData.put("timestamp", System.currentTimeMillis());
            pushData.put("data", payload);
            
            messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/task", pushData);
        } catch (Exception e) {
            log.error("推送任务控制响应失败", e);
        }
    }

    /**
     * 推送规划响应
     * @param deviceId 设备ID
     * @param shortTopic 主题
     * @param payload MQTT消息体
     */
    public void pushPlanningResponse(String deviceId, String shortTopic, String payload) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("deviceId", deviceId);
            pushData.put("type", "planning_reply");
            pushData.put("action", shortTopic);
            pushData.put("timestamp", System.currentTimeMillis());
            pushData.put("data", payload);
            
            messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/planning", pushData);
        } catch (Exception e) {
            log.error("推送规划响应失败", e);
        }
    }

    /**
     * 推送原始MQTT消息（用于调试）
     * @param deviceId 设备ID
     * @param topic MQTT主题
     * @param payload MQTT消息体
     */
    public void pushRawMessage(String deviceId, String topic, String payload) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("deviceId", deviceId);
            pushData.put("topic", topic);
            pushData.put("timestamp", System.currentTimeMillis());
            pushData.put("data", payload);

            messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/raw", pushData);
        } catch (Exception e) {
            log.error("推送原始消息失败", e);
        }
    }

    /**
     * 推送ASM远程调用响应
     * @param deviceId 设备ID
     * @param payload MQTT消息体
     */
    public void pushAsmReply(String deviceId, String payload) {
        try {
            JSONObject json = JSON.parseObject(payload);
            JSONObject pushData = new JSONObject();
            pushData.put("deviceId", deviceId);
            pushData.put("type", "asm_reply");
            pushData.put("function", json.getString("function"));
            pushData.put("status", json.getString("status"));
            pushData.put("pubTimestamp", json.getLong("pub_timestamp"));
            pushData.put("timestamp", System.currentTimeMillis());
            pushData.put("data", payload);

            messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/asm", pushData);
        } catch (Exception e) {
            log.error("推送ASM响应失败", e);
        }
    }

    /**
     * 推送ASM远程调用进度反馈
     * @param deviceId 设备ID
     * @param payload MQTT消息体
     */
    public void pushAsmProgress(String deviceId, String payload) {
        try {
            JSONObject json = JSON.parseObject(payload);
            JSONArray argsArray = json.getJSONArray("args");
            if (argsArray != null && !argsArray.isEmpty()) {
                JSONObject argObj = argsArray.getJSONObject(0);

                JSONObject pushData = new JSONObject();
                pushData.put("deviceId", deviceId);
                pushData.put("type", "asm_progress");
                pushData.put("function", argObj.getString("function"));
                pushData.put("progress", argObj.get("progress"));
                pushData.put("timestamp", System.currentTimeMillis());
                pushData.put("data", payload);

                messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/asm", pushData);
            }
        } catch (Exception e) {
            log.error("推送ASM进度失败", e);
        }
    }

    /**
     * 推送ASM远程调用状态反馈
     * @param deviceId 设备ID
     * @param payload MQTT消息体
     */
    public void pushAsmState(String deviceId, String payload) {
        try {
            JSONObject json = JSON.parseObject(payload);
            JSONArray argsArray = json.getJSONArray("args");
            if (argsArray != null && !argsArray.isEmpty()) {
                JSONObject argObj = argsArray.getJSONObject(0);

                JSONObject pushData = new JSONObject();
                pushData.put("deviceId", deviceId);
                pushData.put("type", "asm_state");
                pushData.put("function", argObj.getString("function"));
                pushData.put("state", argObj.getInteger("state"));
                pushData.put("timestamp", System.currentTimeMillis());
                pushData.put("data", payload);

                messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/asm", pushData);
            }
        } catch (Exception e) {
            log.error("推送ASM状态失败", e);
        }
    }

    /**
     * 推送电池信息
     * @param deviceId 设备ID
     * @param payload MQTT消息体
     */
    public void pushBatteryInfo(String deviceId, String payload) {
        try {
            JSONObject json = JSON.parseObject(payload);
            JSONArray argsArray = json.getJSONArray("args");
            if (argsArray != null && !argsArray.isEmpty()) {
                JSONObject batteryData = argsArray.getJSONObject(0);

                JSONObject pushData = new JSONObject();
                pushData.put("deviceId", deviceId);
                pushData.put("type", "battery");
                pushData.put("timestamp", System.currentTimeMillis());

                // 提取电池信息
                JSONObject battery = new JSONObject();
                battery.put("capacity", batteryData.getDouble("capacity"));      // 电量百分比 0.0~1.0
                battery.put("temperature", batteryData.getDouble("temperature")); // 温度
                battery.put("voltage", batteryData.getDouble("voltage"));      // 电压
                battery.put("current", batteryData.getDouble("current"));      // 电流
                battery.put("charging", batteryData.getBoolean("charging"));   // 充电状态
                battery.put("other", batteryData.getJSONArray("other"));      // 其他设备电量

                pushData.put("data", battery);

                messagingTemplate.convertAndSend("/topic/robot/" + deviceId + "/battery", pushData);
                log.debug("电池信息已推送: {}", battery);
            }
        } catch (Exception e) {
            log.error("推送电池信息失败", e);
        }
    }

    // ========================================
    // 屏幕端播放方案和播报推送
    // ========================================

    /**
     * 推送播放方案变化
     * 推送到 /topic/screen/play-plan
     * @param playPlanData 播放方案数据（Map格式，已转换好前端所需格式）
     */
    public void pushPlayPlanChanged(Map<String, Object> playPlanData) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("type", "play_plan_changed");
            pushData.put("timestamp", System.currentTimeMillis());
            pushData.put("data", playPlanData);

            messagingTemplate.convertAndSend("/topic/screen/play-plan", pushData);
            log.info("[WebSocket] 推送播放方案变化: {}", pushData.toJSONString());
        } catch (Exception e) {
            log.error("推送播放方案变化失败", e);
        }
    }

    /**
     * 推送播放方案禁用（无播放方案）
     * @param planId 被禁用的方案ID
     */
    public void pushPlayPlanDisabled(Long planId) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("type", "play_plan_disabled");
            pushData.put("timestamp", System.currentTimeMillis());

            JSONObject data = new JSONObject();
            data.put("planId", planId);
            data.put("enabled", false);
            pushData.put("data", data);

            messagingTemplate.convertAndSend("/topic/screen/play-plan", pushData);
            log.info("[WebSocket] 推送播放方案禁用: planId={}", planId);
        } catch (Exception e) {
            log.error("推送播放方案禁用失败", e);
        }
    }

    /**
     * 推送播报开始
     * 推送到 /topic/screen/broadcast
     * @param taskId 任务ID
     * @param contentId 内容ID
     * @param taskName 任务名称
     * @param title 播报标题
     * @param content 播报文本
     * @param contentType 内容类型
     * @param audioUrl 音频URL
     * @param audioDuration 音频时长
     */
    public void pushBroadcastStarted(Long taskId, Long contentId, String taskName,
                                     String title, String content, String contentType,
                                     String audioUrl, Integer audioDuration) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("type", "broadcast_started");
            pushData.put("timestamp", System.currentTimeMillis());

            JSONObject data = new JSONObject();
            data.put("broadcasting", true);
            data.put("taskId", taskId);
            data.put("contentId", contentId);
            data.put("taskName", taskName != null ? taskName : "");
            data.put("title", title != null ? title : "");
            data.put("content", content != null ? content : "");
            data.put("contentType", contentType != null ? contentType : "custom");
            data.put("level", "normal");
            data.put("audioUrl", audioUrl != null ? audioUrl : "");
            data.put("audioDuration", audioDuration);
            data.put("startTime", new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));

            pushData.put("data", data);

            messagingTemplate.convertAndSend("/topic/screen/broadcast", pushData);
            log.info("[WebSocket] 推送播报开始: taskId={}, contentId={}", taskId, contentId);
        } catch (Exception e) {
            log.error("推送播报开始失败", e);
        }
    }

    /**
     * 推送播报结束
     * 推送到 /topic/screen/broadcast
     */
    public void pushBroadcastEnded() {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("type", "broadcast_ended");
            pushData.put("timestamp", System.currentTimeMillis());

            JSONObject data = new JSONObject();
            data.put("broadcasting", false);
            pushData.put("data", data);

            messagingTemplate.convertAndSend("/topic/screen/broadcast", pushData);
            log.info("[WebSocket] 推送播报结束");
        } catch (Exception e) {
            log.error("推送播报结束失败", e);
        }
    }

    /**
     * 推送屏幕端连接确认
     */
    public void pushConnected(String sessionId) {
        try {
            JSONObject pushData = new JSONObject();
            pushData.put("type", "connected");
            pushData.put("timestamp", System.currentTimeMillis());

            JSONObject data = new JSONObject();
            data.put("sessionId", sessionId);
            data.put("status", "connected");
            pushData.put("data", data);

            messagingTemplate.convertAndSend("/topic/screen/connect", pushData);
            log.info("[WebSocket] 推送连接确认: sessionId={}", sessionId);
        } catch (Exception e) {
            log.error("推送连接确认失败", e);
        }
    }
}
