package cn.component.message.mq.base;

import cn.api.websocket.AtvWebSocket;
import cn.component.RedisKit;
import cn.component.influxdb.InfluxDbUtil;
import cn.component.message.mq.AtvUpdateSender;
import cn.component.rule.base.FillRuleUtil;
import cn.facade.abs.IService;
import cn.facade.constant.WebsocketConst;
import cn.facade.util.UniAppPush;
import cn.pojo.atv.*;
import cn.pojo.atv.vo.PopupResult;
import cn.pojo.entity.TSysUser;
import cn.util.core.IsKit;
import cn.util.core.LogKit;
import cn.util.core.TypeKit;
import cn.util.time.TimeKit;
import com.alibaba.fastjson2.JSONObject;
import com.rabbitmq.client.Channel;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;


public abstract class HandleRabbitBase extends IService {

    @Autowired
    protected AtvUpdateSender atvUpdateSender;
    @Autowired
    protected AtvWebSocket atvWebSocket;
    @Autowired
    protected RedisKit redisCache;
    @Autowired
    protected InfluxDbUtil influxDbUtil;
    @Resource
    protected FillRuleUtil ruleService;

    protected List<PopupResult> popupResultList = null;
    protected List<AtvEquipment> atvEquipments = null;

    protected List<AtvWarnLog> atvWarnLogs = null;
    protected List<AtvBoardCardFault> atvBoardCardFaults = null;
    protected List<AtvTrainWorkingLog> atvTrainWorkingLogs = null;
    protected List<AtvBoardCard> atvBoardCards = null;
    protected AtvLine atvLine = null;
    protected AtvCountry atvCountry = null;
    protected AtvArea atvArea = null;
    protected AtvTrain atvTrain = null;


    /***处理Rabbit发来的消息,并写入对应库表中*/
    @RabbitHandler
    public void handle(JSONObject jsonObject, Channel channel, Message msg) throws IOException {
        LogKit.info("【调试-2】收到客户端消息" + jsonObject);
        if (IsKit.isNull(jsonObject)) {
            LogKit.info("接收到的RabbitMQ消息为空");
            return;
        }
        long time = System.currentTimeMillis();
        try {
            atvEquipments = new ArrayList<>();
            atvBoardCardFaults = new ArrayList<>();
            atvWarnLogs = new ArrayList<>();
            atvTrainWorkingLogs = new ArrayList<>();
            atvBoardCards = new ArrayList<>();
            popupResultList = new ArrayList<>();
            Integer rawCode = jsonObject.getInteger("cmd_code");
            if (IsKit.isNull(rawCode)) {
                LogKit.info("协议的命令码不对：" + rawCode);
                return;
            }
            //用于调试 将JSON格式的消息写入文件
            //write(cmd_code, jsonObject);

            String countryCode = jsonObject.getString("country");
            atvCountry = (AtvCountry) redisCache.hget("country", countryCode);
            if (IsKit.isNull(atvCountry)) {
                LogKit.info("未找到国家：" + jsonObject);
                return;
            }
            String cityNo = jsonObject.getString("cityNo");
            atvArea = (AtvArea) redisCache.hget("area", atvCountry.getId() + cityNo);
            if (IsKit.isNull(atvArea)) {
                LogKit.info("未找到城市：" + jsonObject);
                return;
            }
            String metroLine = jsonObject.getString("metroLine");
            atvLine = (AtvLine) redisCache.hget("line", atvArea.getId() + metroLine);
            if (IsKit.isNull(atvLine)) {
                LogKit.info("未找到线路：" + jsonObject);
                return;
            }

            String vehicleNo = jsonObject.getString("vehicleNo");
            atvTrain = (AtvTrain) redisCache.hget("train", atvLine.getId() + vehicleNo);
            if (IsKit.isNull(atvTrain)) {
                LogKit.info("未找到列车：" + jsonObject);
                return;
            }
            //发送到线路
            String userIdLine = countryCode + cityNo + metroLine;
            //发送到车辆
            String userIdTrain = userIdLine + vehicleNo;
            _distribute(rawCode, jsonObject, userIdLine, userIdTrain);
            _sendPopMsg(userIdLine);
            _sendMessage();
            LogKit.info("解析协议中的命令码(" + rawCode + "),耗时:" + (System.currentTimeMillis() - time));
        } finally {
            if (IsKit.isNotNull(atvWarnLogs)) {
                atvWarnLogs.clear();
            }
            if (IsKit.isNotNull(atvBoardCardFaults)) {
                atvBoardCardFaults.clear();
            }
            if (IsKit.isNotNull(atvTrainWorkingLogs)) {
                atvTrainWorkingLogs.clear();
            }
            if (IsKit.isNotNull(atvBoardCards)) {
                atvBoardCards.clear();
            }
//            channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
//            LogKit.info("【调试-2】消息处理完成--------------------------------------------------------------------------------\n");
        }
    }

    protected abstract void _distribute(Integer rawCode, JSONObject jsonObject, String userIdLine, String userIdTrain);

    protected List<AtvBoardCardFault> _findByNowBoardCardFault(
            String trainId, Integer faultSource,
            String address, String phenomenon) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("trainId", trainId);
        paramsMap.put("faultSource", faultSource);
        paramsMap.put("address", address);
        paramsMap.put("phenomenon", phenomenon);
//        paramsMap.put("nowDate", TimeKit.getNowDate());
        return TypeKit.cast(daoService.getEntityListBySql("atv_findByNowBoardCardFault", paramsMap, AtvBoardCardFault.class));
    }

    protected List<AtvWarnLog> _findByNowWarnLog(
            String lineId, String trainId, String carriageId,
            String equipmentId, String boardCardId, Integer warnType,
            Integer faultType, String faultNo) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("lineId", lineId);
        paramsMap.put("trainId", trainId);
        paramsMap.put("carriageId", carriageId);
        paramsMap.put("equipmentId", equipmentId);
        paramsMap.put("boardCardId", boardCardId);
        paramsMap.put("warnType", warnType);//4设备异常
        paramsMap.put("faultType", faultType);
        paramsMap.put("faultNo", faultNo);
        paramsMap.put("nowDate", TimeKit.getNowDate());
        return TypeKit.cast(daoService.getEntityListBySql("atv_findByNowWarnLog", paramsMap, AtvWarnLog.class));
    }

    protected void _pushFaultMsg(String text, AtvLine atvLine) {
        String title = "新的故障工单";
        if (IsKit.isNullOrEmpty(atvLine) || IsKit.isNullOrEmpty(atvLine.getWorkers())) {
            return;
        }
        String[] usernames = atvLine.getWorkers().split(",");
        List<TSysUser> loginUserList = sysBaseService.getUserListByNames(usernames);
        for (TSysUser loginUser : loginUserList) {
            if (IsKit.isNullOrEmpty(loginUser) && IsKit.isNullOrEmpty(loginUser.getClientId())) {
                UniAppPush.pushMessageToSingle(loginUser.getClientId(), title, text);
            }
        }
    }

    /*发送弹窗websocket开始*/
    protected void _sendPopMsg(String userIdLine) {
        if (popupResultList.size() > 0) {
            JSONObject webJson = new JSONObject();
            webJson.put(WebsocketConst.MSG_CMD, "popupResult");
            webJson.put(WebsocketConst.MSG_TXT, popupResultList);
            atvWebSocket.sendOneMessage("web", userIdLine, webJson.toString());
        }
    }

    //发送消息
    protected void _sendMessage() {
        JSONObject updateObject = new JSONObject();
        updateObject.put("atvWarnLog", atvWarnLogs);
        updateObject.put("atvBoardCardFault", atvBoardCardFaults);
        updateObject.put("atvTrainWorkingLog", atvTrainWorkingLogs);
        updateObject.put("atvEquipment", atvEquipments);
        updateObject.put("atvBoardCard", atvBoardCards);
        atvUpdateSender.sendMessage(updateObject, 1L);
        //atvWarnLogService.saveOrUpdateBatch(atvWarnLogs);
        //atvBoardCardFaultService.saveOrUpdateBatch(atvBoardCardFaults);
        //atvTrainWorkingLogService.saveOrUpdateBatch(atvTrainWorkingLogs);
        //atvBoardCardService.updateBatchById(atvBoardCards);
        //atvEquipmentService.updateBatchById(atvEquipments);
    }

    /**
     * 获取设备类型 @param equipmentType 设备类型1-15
     */
    @NotNull
    @Contract(pure = true)
    protected String _equipmentType(int equipmentType) {
        return switch (equipmentType) {
            case 1 -> "广播主机";
            case 2 -> "客室主机";
            case 3 -> "广播控制盒";
            case 4 -> "报警器";
            case 5 -> "监控触摸屏";
            case 6 -> "播控器";
            case 7 -> "磁盘录像机";
            case 8 -> "动态地图";
            case 9 -> "LCD显示屏";
            case 10 -> "终点LED显示器";
            case 11 -> "端墙LED显示器";
            case 12 -> "车外LED显示器";
            case 13 -> "路况摄像机";
            case 14 -> "司机室摄像机";
            case 15 -> "客室摄像机";
            default -> "未知";
        };
    }

    /**
     * BJTU 2022.11.9 设备类型识别
     *
     * @param typeName 设备名称
     */
    protected Integer _stringEquipmentType(String typeName) {
        String[] names = {"", "PAPCU", "PASCU", "PADCU", "PECU", "TLCD", "PLAYCTRL", "NVR", "DRAM", "LCD", "TDU", "IDU",
                "ODU", "SCAM", "CAM", "FCAM", "SW"};
        for (int i = 1; i < names.length; i++) {
            if (typeName.startsWith(names[i])) {
                return i;
            }
        }
        return 0;
    }

    /**
     * 获取板卡类型
     *
     * @param boardCardType 板卡类型1-8
     */
    protected String _boardCardType(int boardCardType) {
        return switch (boardCardType) {
            case 1 -> "电源板";
            case 2 -> "音频板";
            case 3 -> "控制板";
            case 4 -> "重连板";
            case 5 -> "功放板";
            case 6 -> "报警器";
            case 7 -> "控制盒";
            case 8 -> "MVB板";
            default -> "未知";
        };
    }

    /**
     * 将接收的JSON消息输出到本地文件中
     *
     * @param cmdCode    消息编号
     * @param jsonObject JSON格式消息
     */
    protected 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(R)" + entry.getKey() + ".json");
                    FileOutputStream out;
                    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);
    }

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