package cn.api.websocket;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

import cn.component.message.mq.AtvCmd1Sender;

import javax.annotation.Resource;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import cn.component.context.SpringContextKit;
import cn.orm.abs.ISqlToyDao;
import cn.orm.sqltoy.plus.Wrappers;
import cn.orm.sqltoy.plus.query.LambdaQueryWrapper;
import cn.pojo.atv.AtvTts;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson2.JSONObject;
import cn.api.atv.AtvTtsCtrl;
import cn.component.message.mq.AtvSender;
import cn.facade.constant.AtvConst;
import cn.facade.constant.WebsocketConst;
import cn.service.atv.IAtvTrainService;
import cn.util.core.IsKit;
import cn.util.core.LogKit;


@Component
//@ServerEndpoint("/atv/websocket/{platform}/{userId}")
@ServerEndpoint("/atv/websocket/{platform}/{userId}")
public class AtvWebSocket {
    /**
     * 传输数据最大字节
     */
    public static final int MAX_TEXT_MESSAGE_SIZE = 100 * 1024 * 1024;

    @Resource
    private AtvSender atvSender;
    @Resource
    private AtvCmd1Sender atvCmd1Sender;
    @Resource
    IAtvTrainService atvTrainService;


    /**
     * 此处是解决无法注入的关键
     * <p>
     */
     /* 原来的会无缘无故断开链接 目前不用*/
     private static ApplicationContext applicationContext;
     public static void setApplicationContext(ApplicationContext applicationContext) {
        AtvWebSocket.applicationContext = applicationContext;
     }

    private static CopyOnWriteArraySet<AtvWebSocket> webSockets = new CopyOnWriteArraySet<AtvWebSocket>();
    private static ConcurrentHashMap<String, List<Session>> equipments = new ConcurrentHashMap<String, List<Session>>();
    private static ConcurrentHashMap<String, List<Session>> ttss = new ConcurrentHashMap<String, List<Session>>();
    private static ConcurrentHashMap<String, List<Session>> webs = new ConcurrentHashMap<String, List<Session>>();
    private Session session;

    /** 服务器有响应数据触发:收到客户端信息*/
    @OnMessage
    public void onMessage(String message) {
        if (IsKit.isNullOrEmpty(message)) {
            return;
        }
        /* sam del
        if (message.contains("PING")) {
            LogKit.info("【atvWebsocket消息】收到PING消息");
            return;
        }*/
        //todo 现在有个定时任务刷，应该去掉
        LogKit.info("【atvWebsocket消息】收到客户端消息:" + message);
        try {
            JSONObject jsonObject = JSONObject.parseObject(message);
            Integer cmd_code = jsonObject.getInteger("cmd_code");
            LogKit.info("【AtvWebSocket-cmd】" + cmd_code);
            if (IsKit.isNotNullOrEmpty(cmd_code)) {
              if (cmd_code.equals(1)) {
                    //sam old atvCmd1Sender = applicationContext.getBean(AtvCmd1Sender.class);
                    atvCmd1Sender = SpringContextKit.getBean(AtvCmd1Sender.class);
                    atvCmd1Sender.sendMessage(jsonObject, 1);
                } else {
                   //sam old atvSender = applicationContext.getBean(AtvSender.class);
                    atvSender = SpringContextKit.getBean(AtvSender.class);
                    atvSender.sendMessage(jsonObject, 1);
                }
            }
        } catch (Exception e) {
            LogKit.info("【atvWebsocket消息-1】收到非JSON数据：" + message);
            LogKit.info("【atvWebsocket消息-2】收到非JSON数据：" + e.getMessage());
        }
        JSONObject obj = new JSONObject();
        obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_CHECK);//业务类型
        obj.put(WebsocketConst.MSG_TXT, "心跳响应");//消息内容
        session.getAsyncRemote().sendText(obj.toJSONString());
    }

    /**
     * 建立连接成功调用
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "platform") String platform, @PathParam(value = "userId") String userId) {
        LogKit.info("【atvWebsocket->onOpen-platform1【cmd_code5——Debug】:" + platform);
        try {
            this.session = session;
            session.setMaxTextMessageBufferSize(MAX_TEXT_MESSAGE_SIZE);
            session.setMaxBinaryMessageBufferSize(MAX_TEXT_MESSAGE_SIZE);
            if (AtvConst.WS_MSG_EQUIP.equalsIgnoreCase(platform)) {
                List<Session> equipment = IsKit.isNotNull(equipments.get(userId)) ? equipments.get(userId) : new ArrayList<Session>();
                equipment.add(session);
                equipments.put(userId, equipment);
                String[] strings = userId.split(AtvConst.CMD_SEP);
                //通知web端车辆上线 4?,1 ?
                if (strings.length == 4 && equipment.size() == 1) {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put(WebsocketConst.MSG_CMD, "trainOnlineStatus");
                    JSONObject json = new JSONObject();
                    json.put("countryCode", strings[0]);
                    json.put("areaCode", strings[1]);
                    json.put("lineSn", strings[2]);
                    json.put("trainSn", strings[3]);
                    json.put("onlineStatus", 1);
                    jsonObject.put(WebsocketConst.MSG_TXT, json);
                    String userIdLine = strings[0] + strings[1] + strings[2];
                    String userIdTrain = userIdLine + strings[3];
                    sendOneMessage("web", userIdLine, jsonObject.toString());
                    sendOneMessage("web", userIdTrain, jsonObject.toString());
                    atvTrainService = SpringContextKit.getBean(IAtvTrainService.class);
                    // 根据国家、地区、线路、车辆编号更新车辆在线状态
                    atvTrainService.trainOnlineStatus(strings[0], strings[1], strings[2], strings[3], 1);
                }
            } else if (AtvConst.WS_MSG_TTS.equalsIgnoreCase(platform)) {
                LogKit.info("【atvWebsocket->onOpen-platform2【cmd_code5——Debug】:" + platform);
                List<Session> tts = IsKit.isNotNull(ttss.get(userId)) ? ttss.get(userId) : new ArrayList<Session>();
                LogKit.info("【atvWebsocket->onOpen-platform3【cmd_code5——Debug】:" + tts);
                LogKit.info("【atvWebsocket->onOpen-platform4【cmd_code5——Debug】:" + session);
                LogKit.info("【atvWebsocket->onOpen-platform5【cmd_code5——Debug】:" + userId);
                tts.add(session);
                ttss.put(userId, tts);
            } else if (AtvConst.WS_MSG_WEB.equalsIgnoreCase(platform)) {
                List<Session> web = IsKit.isNotNull(webs.get(userId)) ? webs.get(userId) : new ArrayList<Session>();
                web.add(session);
                webs.put(userId, web);
            } else {
                return;
            }
            webSockets.add(this);
            LogKit.info("【atvWebsocket消息】新连接，在线车辆数:" + equipments.size() + "，TTS在线车辆数:" + ttss.size() + "，WEB在线车辆/线路数:" + webs.size() + "，总数:" + webSockets.size());
        } catch (Exception e) {
            LogKit.info(e.getMessage());
        }
        JSONObject obj = new JSONObject();
        obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_CHECK);//业务类型
        obj.put(WebsocketConst.MSG_TXT, "心跳响应");//消息内容
        session.getAsyncRemote().sendText(obj.toJSONString());
    }
    /**
     * 服务器有 响应数据 触发
     */
    @OnError
    public void onError(Session session, Throwable throwable) {
        LogKit.info("连接{}发生错误!", session.getId());
        throwable.printStackTrace();
    }
    /**
     * 连接关闭时触发
     */
    @OnClose
    public void onClose() {
        try {
            /**设备状态*/
            for (String key : equipments.keySet()) {
                int count = 0;
                for (Iterator<Session> sessionIterator = equipments.get(key).iterator(); sessionIterator.hasNext(); ) {
                    Session session = sessionIterator.next();
                    if (session == this.session) {
                        sessionIterator.remove();
                        webSockets.remove(this);
                        if (!sessionIterator.hasNext() && count == 0) {
                            equipments.remove(key);
                            String[] strings = key.split(AtvConst.CMD_SEP);
                            if (strings.length == 4) {  //通知web端车辆掉线
                                JSONObject jsonObject = new JSONObject();
                                jsonObject.put(WebsocketConst.MSG_CMD, "trainOnlineStatus");
                                JSONObject json = new JSONObject();
                                json.put("countryCode", strings[0]);
                                json.put("areaCode", strings[1]);
                                json.put("lineSn", strings[2]);
                                json.put("trainSn", strings[3]);
                                json.put("onlineStatus", 2);
                                jsonObject.put(WebsocketConst.MSG_TXT, json);
                                String userIdLine = strings[0] + strings[1] + strings[2];
                                String userIdTrain = userIdLine + strings[3];
                                sendOneMessage("web", userIdLine, jsonObject.toString());
                                sendOneMessage("web", userIdTrain, jsonObject.toString());
                                atvTrainService = SpringContextKit.getBean(IAtvTrainService.class);

                                atvTrainService.trainOnlineStatus(strings[0], strings[1], strings[2], strings[3], 2);
                            }
                        }
                        LogKit.info("【atvWebsocket消息】连接断开，在线车辆数:" + equipments.size() + "，TTS在线车辆数:" + ttss.size() + "，WEB在线车辆/线路数:" + webs.size() + "，总数:" + webSockets.size());
                        return;
                    }
                    count++;
                }
            }
            /*TTS设备*/
            for (String key : ttss.keySet()) {
                int count = 0;
                for (Iterator<Session> sessionIterator = ttss.get(key).iterator(); sessionIterator.hasNext(); ) {
                    Session session = sessionIterator.next();
                    if (session == this.session) {
                        sessionIterator.remove();
                        webSockets.remove(this);
                        if (!sessionIterator.hasNext() && count == 0) {
                            ttss.remove(key);
                        }
                        LogKit.info("【atvWebsocket消息】连接断开，在线车辆数:" + equipments.size() + "，TTS在线车辆数:" + ttss.size() + "，WEB在线车辆/线路数:" + webs.size() + "，总数:" + webSockets.size());
                        return;
                    }
                    count++;
                }
            }
            /*WEB网页*/
            for (String key : webs.keySet()) {
                int count = 0;
                for (Iterator<Session> sessionIterator = webs.get(key).iterator(); sessionIterator.hasNext(); ) {
                    Session session = sessionIterator.next();
                    if (session == this.session) {
                        sessionIterator.remove();
                        webSockets.remove(this);
                        if (!sessionIterator.hasNext() && count == 0) {
                            webs.remove(key);
                        }
                        LogKit.info("【atvWebsocket消息】连接断开，在线车辆数:" + equipments.size() + "，TTS在线车辆数:" + ttss.size() + "，WEB在线车辆/线路数:" + webs.size() + "，总数:" + webSockets.size());
                        return;
                    }
                    count++;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 此为广播消息(发送文本消息)
     * session.getAsyncRemote()表示异步发送
     * session.getBasicRemote()表示同步发送
     *
     * @param message 消息内容
     */
    public void sendAllMessage(String message) {
        LogKit.info("【atvWebsocket消息】广播消息:" + message);
        for (AtvWebSocket webSocket : webSockets) {
            try {
                if (webSocket.session.isOpen()) {
                    webSocket.session.getAsyncRemote().sendText(message);
                }
            } catch (Exception e) {
                LogKit.info(e.getMessage());
            }
        }
    }

    /**
     * 此为单点消息
     *
     * @param platform 平台类型，equipment设备状态信息上传、tts文字转语音、web网页
     * @param userId   发送的客户端ID
     * @param message  消息
     */
    public void sendOneMessage(String platform, String userId, String message) {
        if (AtvConst.WS_MSG_EQUIP.equalsIgnoreCase(platform)) {
            List<Session> equipment = equipments.get(userId);
            if (IsKit.isNotNullOrEmpty(equipment)) {
                LogKit.info("【atvWebsocket消息】 单点消息:" + message);
                for (Session session : equipment) {
                    try {
                        if (IsKit.isNotNull(session) && session.isOpen()) {
                            session.getAsyncRemote().sendText(message);
                        }
                    } catch (Exception e) {
                        LogKit.info(e.getMessage());
                    }
                }
            }
        } else if (AtvConst.WS_MSG_TTS.equalsIgnoreCase(platform)) {
            List<Session> tts = ttss.get(userId);
            if (IsKit.isNotNullOrEmpty(tts)) {
                LogKit.info("【atvWebsocket消息】 单点消息:" + message);
                for (Session session : tts) {
                    try {
                        if (IsKit.isNotNull(session) && session.isOpen()) {
                            session.getAsyncRemote().sendText(message);
                        }
                    } catch (Exception e) {
                        LogKit.info(e.getMessage());
                    }
                }
            }
        } else if (AtvConst.WS_MSG_WEB.equalsIgnoreCase(platform)) {
            List<Session> web = webs.get(userId);
            if (IsKit.isNotNullOrEmpty(web)) {
                LogKit.info("web" + userId);
                LogKit.info("【atvWebsocket消息】 单点消息:" + message);
                for (Session session : web) {
                    try {
                        if (IsKit.isNotNull(session) && session.isOpen()) {
                            session.getAsyncRemote().sendText(message);
                        }
                    } catch (Exception e) {
                        LogKit.info(e.getMessage());
                    }
                }
            }
        } else {
            return;
        }
    }

    /**
     * 此为单点消息(多人)
     *
     * @param platform 平台类型，equipment设备状态信息上传、tts文字转语音、web网页
     * @param userIds  发送的客户端ID数组
     * @param message  消息
     */
    public void sendMoreMessage(String platform, String[] userIds, String message) {
        for (String userId : userIds) {
            if (AtvConst.WS_MSG_EQUIP.equalsIgnoreCase(platform)) {
                List<Session> equipment = equipments.get(userId);
                if (IsKit.isNotNullOrEmpty(equipment)) {
                    LogKit.info("【atvWebsocket消息】 单点消息(多人):" + message);
                    for (Session session : equipment) {
                        try {
                            if (IsKit.isNotNull(session) && session.isOpen()) {
                                session.getAsyncRemote().sendText(message);
                            }
                        } catch (Exception e) {
                            LogKit.info(e.getMessage());
                        }
                    }
                }
            } else if (AtvConst.WS_MSG_TTS.equalsIgnoreCase(platform)) {
                List<Session> tts = ttss.get(userId);
                if (IsKit.isNotNullOrEmpty(tts)) {
                    LogKit.info("【atvWebsocket消息】 单点消息(多人):" + message);
                    for (Session session : tts) {
                        try {
                            if (IsKit.isNotNull(session) && session.isOpen()) {
                                session.getAsyncRemote().sendText(message);
                            }
                        } catch (Exception e) {
                            LogKit.info(e.getMessage());
                        }
                    }
                }
            } else if (AtvConst.WS_MSG_WEB.equalsIgnoreCase(platform)) {
                List<Session> web = webs.get(userId);
                if (IsKit.isNotNullOrEmpty(web)) {
                    LogKit.info("【atvWebsocket消息】 单点消息(多人):" + message);
                    for (Session session : web) {
                        try {
                            if (IsKit.isNotNull(session) && session.isOpen()) {
                                session.getAsyncRemote().sendText(message);
                            }
                        } catch (Exception e) {
                            LogKit.info(e.getMessage());
                        }
                    }
                }
            } else {
                return;
            }
        }
    }

    /**
     * 转换或发送TTS语音
     *
     * @param type      0为文字转语音，1为开始播放
     * @param userId    发送的TTS客户端（国家编号+城市编号+线路编号+列车编号）
     * @param messageId TTS消息ID
     * @param message   消息内容
     */
    public Boolean sendTtsMessage(int type, String userId, String messageId, String message) {
        LogKit.info("【atvWebsocket->cmd_code5_01:】TTS_MSg(userId):" + userId);
        LogKit.info("【atvWebsocket->cmd_code5_02:】TTS_MSg(type):" + type);
        LogKit.info("【atvWebsocket->cmd_code5_03:】TTS_MSg_MSg(turnTts):" + AtvTtsCtrl.turnTts.get(userId + messageId));
        LogKit.info("【atvWebsocket->cmd_code5_04:】TTS_MSg(userId):" + AtvTtsCtrl.playTts.get(userId + messageId));
        //原来的List<Session> sessionList = type == 0 ? AtvTtsCtrl.turnTts.get(userId + messageId) : AtvTtsCtrl.playTts.get(userId + messageId);
        List<Session> sessionList = type == 0 ? AtvTtsCtrl.turnTts.get(userId) : AtvTtsCtrl.playTts.get(userId);
        LogKit.info("【atvWebsocket->cmd_code5_1:】TTS_MSg:" + sessionList);
        if (IsKit.isNull(sessionList)) {
            sessionList = new ArrayList<>();
        }
        List<Session> tts = ttss.get(userId);
        LogKit.info("【atvWebsocket->cmd_code5_2】TTS_MSg:" + tts);
        if (IsKit.isNotNullOrEmpty(tts)) {
            for (Session session : tts) {
                try {
                    if (IsKit.isNotNull(session) && session.isOpen() && !sessionList.contains(session)) {
                        LogKit.info("【atvWebsocket->cmd_code5_3】TTS_MSg:" + message);
                        session.getAsyncRemote().sendText(message);
                        sessionList.add(session);
                        if (type == 0) {
                            AtvTtsCtrl.turnTts.put(userId + messageId, sessionList);
                        } else {
                            AtvTtsCtrl.playTts.put(userId + messageId, sessionList);
                        }
                        break;
                    }
                } catch (Exception e) {
                    LogKit.info("【atvWebsocket->cmd_code5_4】TTS_MSg:" + e.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 某列车的所有连接的equipment
     *
     * @param userId  发送的TTS客户端（国家编号+_+城市编号+_+线路编号+_+列车编号）
     * @param message 消息内容
     */
    public boolean sendEquipmentMessage(String userId, String message) {
        LogKit.info("sendEquipmentMessage-userId:" + userId);
        LogKit.info("sendEquipmentMessage-message:" + message);
        List<Session> equipment = equipments.get(userId);
        LogKit.info("sendEquipmentMessage-equipmentsession:" + equipment);
        boolean result = false;
        if (IsKit.isNotNullOrEmpty(equipment)) {
            for (Session session : equipment) {
                try {
                    if (IsKit.isNotNull(session) && session.isOpen()) {
                        LogKit.info("【atvWebsocket消息】发送命令到设备消息:" + message);
                        session.getAsyncRemote().sendText(message);
                        result = true;
                    }
                } catch (Exception e) {
                    LogKit.info(e.getMessage());
                }
            }
        }
        return result;
    }

    private static int count = 0;
    private Map<Integer, LinkedList<JSONObject>> map = new LinkedHashMap<>();

    public void write(Integer cmdCode, JSONObject jsonObject) {
        count += 1;
        if (!map.containsKey(cmdCode)) {
            LinkedList<JSONObject> list = new LinkedList<>();
            list.add(jsonObject);
            map.put(cmdCode, list);
        } else {
            map.get(cmdCode).add(jsonObject);
        }
        if (count >= 100) {
            try {
                File file;
                for (Map.Entry<Integer, LinkedList<JSONObject>> entry : map.entrySet()) {
                    file = new File("cmdCode(S)" + entry.getKey() + ".json");
                    FileOutputStream out = null;
                    if (!file.exists()) {
                        file.createNewFile();
                        out = new FileOutputStream(file);
                    } else {
                        out = new FileOutputStream(file, true);
                    }
                    OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
                    for (JSONObject object : entry.getValue()) {
                        writer.write(object.toString());
                        writer.write("\n");
                    }
                    writer.close();
                    LogKit.info("Write to " + file.getName() + " : " + entry.getValue().size());
                }
            } catch (Exception e) {
                LogKit.info(e.toString());
            } finally {
                count = 0;
                map.clear();
            }
        }
        LogKit.info("Receive JSON " + count);
    }

    /**
     * 喊话
     */
    public Boolean sendVoiceMessage(String userId, String messageId, byte[] file) {
        List<Session> sessionList = AtvTtsCtrl.playTts.get(userId + messageId);
        if (IsKit.isNull(sessionList)) {
            sessionList = new ArrayList<Session>();
        }
        List<Session> tts = ttss.get(userId);
        // readFile

        ByteBuffer buff = ByteBuffer.wrap(file);
        if (IsKit.isNotNullOrEmpty(tts)) {
            for (Session session : tts) {
                try {
                    if (IsKit.isNotNull(session) && session.isOpen() && !sessionList.contains(session)) {
                        LogKit.info("【atvWebsocket消息】语音消息:");
                        session.getAsyncRemote().sendBinary(buff);
                        // 发送语音
                        sessionList.add(session);
                        AtvTtsCtrl.playTts.put(userId + messageId, sessionList);
                        break;
                    }
                } catch (Exception e) {
                    LogKit.info(e.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

}
