package com.sptg.repeater.rabbitmq.consumer;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sptg.repeater.dh.DHExecute;
import com.sptg.repeater.utils.HttpUti;
import com.sptg.repeater.vo.CommonValues;
import com.sptg.repeater.vo.Response;
import org.apache.log4j.Logger;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * topic（主题）大豪信息 消费者
 */
@Component
public class TopicDHConsumer {
    private static final Logger logger = Logger.getLogger(TopicDHConsumer.class);

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 大豪卡下发指令缓存名称
     */
    private final static String DH_CARD_BATCH_CACHE_NAME = "sptg:repeater:batchdhcard";

    @Autowired
    private DHExecute dhExecute;

    @Autowired
    private CommonValues cv;

    @RabbitHandler
    @RabbitListener(queues = "TRANSIENT_DH") //监听的队列名称 TRANSIENT_DH
    public void transientDH(Object object) {
        JSONObject data = objToJson(object);
        try {
            DHExecute_TRANSIENT(data);
        } catch (Exception e){
            logger.error("TRANSIENT_DH消费者异常", e);
            String errorMsg = e.getMessage();
            // 发送异常结果给常运智慧项目
            HttpUti.postLzAbnormal(data, errorMsg, null);
        }
    }

    @RabbitHandler
    @RabbitListener(queues = "PERSISTENT_DH")  //监听的队列名称 PERSISTENT_DH
    public void persistentDH(Object object) {
        JSONObject data = objToJson(object);
        try {
            Thread.sleep(2000);
            logger.info("PERSISTENT_DH内容：" + data);
            DHExecute_PERSISTENT(data);
        } catch (Exception e){
            logger.error("PERSISTENT_DH消费者异常", e);
            String errorMsg = e.getMessage();
            // 发送异常结果给常运智慧项目
            HttpUti.postLzAbnormal(data, errorMsg, null);
        }
    }

    /*@RabbitHandler
    @RabbitListener(queues = "DH_DEAD_LETTER_QUEUE_DH") //监听死信队列名称 DH_DEAD_LETTER_QUEUE
    public void deadLetterDH(Object object) {
        try {
            HashOperations<String, String, String> hashOperations = this.redisTemplate.opsForHash();
            Long size = hashOperations.size(DH_CARD_CACHE_NAME);
            if(size > 0){
                Map<String, String> map = hashOperations.entries(DH_CARD_CACHE_NAME);
                int index = 0;
                Map<String, String[]> sendData = new HashMap<>();
                for(String key : map.keySet()){
                    String jsonStr = map.get(key);
                    JSONObject jsonData = JSONUtil.parseObj(jsonStr);
                    // 判断json是否有值
                    if(isNullData(jsonData)){
                        return;
                    }else{
                        JSONObject data =  JSONUtil.parseObj(jsonData.get("data"));
                        String serialNumber = jsonData.getStr("serialNumber");
                        String adminPwd = jsonData.getStr("adminPwd");
                        String code = jsonData.getStr("code");
                        String id = jsonData.getStr("id");
                        String cardNo = dhExecute.formatCardNo(data.getStr("cardNo"));
                        if(StrUtil.isBlank(cardNo)){
                            continue;
                        }
                        String sDate = data.getStr("beginDate");
                        String eDate = data.getStr("endDate");
                        Date startDate = DateUtil.parse(sDate);
                        String startDateStr = DateUtil.format(startDate, "yyyyMMddHHmmss");
                        Date endDate = DateUtil.parse(eDate);
                        String endDateStr = DateUtil.format(endDate, "yyyyMMddHHmmss");
                        if(sendData.containsKey(serialNumber)){
                            String[] dataStr = sendData.get(serialNumber);
                            //0:卡ID集串，1：开始时间串，2：结束时间串，3：卡个数，4：设备序列号，5：设备管理密码
                            dataStr[0] = dataStr[0] + cardNo;
                            dataStr[1] = dataStr[1] + startDateStr;
                            dataStr[2] = dataStr[2] + endDateStr;
                            dataStr[3] = (Integer.parseInt(dataStr[3]) + 1) + "";
                            dataStr[4] = serialNumber;
                            dataStr[5] = adminPwd;
                            dataStr[6] = dataStr[6] + "," + id;
                            dataStr[7] = code;
                        }else{
                            String[] dataStr = new String[8];
                            dataStr[0] = cardNo;
                            dataStr[1] = startDateStr;
                            dataStr[2] = endDateStr;
                            dataStr[3] = "1";
                            dataStr[4] = serialNumber;
                            dataStr[5] = adminPwd;
                            dataStr[6] = id;
                            dataStr[7] = code;
                            sendData.put(serialNumber, dataStr);
                        }
                        index ++;
                        if(index == 100){
                            break;
                        }
                    }
                }
                for(String serialNumber: sendData.keySet()){
                    Response res = dhExecute.checkDeviceOnLineStatus(serialNumber, new JSONObject());
                    String data = JSONUtil.toJsonStr(res.getData());
                    String dataStr2 = data.replaceAll("\\\\", "");
                    JSONObject jsonObject = JSONUtil.parseObj(dataStr2);
                    Integer isOnline = (Integer) jsonObject.get("status");
                    if(isOnline == 0){ //设备不在线

                    }else if(isOnline == 1){ //设备在线
                        String[] dataStr = sendData.get(serialNumber);
                        Integer keyCount = Integer.parseInt(dataStr[3]);
                        HashOperations<String, Object, Object> hashOperations2 = this.redisTemplate.opsForHash();
                        if(keyCount == 1){
                            dhExecute.addMoreKey(serialNumber, dataStr[5], null, dataStr[6], dataStr[0], 0, dataStr[1], dataStr[2], keyCount);
                            String instructId = dataStr[6];
                            hashOperations2.delete(DH_CARD_CACHE_NAME, instructId);
                            hashOperations2.put(DH_CARD_BATCH_CACHE_NAME, dataStr[6], dataStr[6]);
                        }else{
                            String serialStr = System.currentTimeMillis() + "";
                            dhExecute.addMoreKey(serialNumber, dataStr[5], null, serialStr, dataStr[0], 1, dataStr[1], dataStr[2], keyCount);
                            String[] split = dataStr[6].split(",");
                            for(String instructId : split){
                                hashOperations2.delete(DH_CARD_CACHE_NAME, instructId);
                            }
                            hashOperations2.put(DH_CARD_BATCH_CACHE_NAME, serialStr, dataStr[6]);
                        }
                    }
                }
            }
        } catch (Exception e){
            logger.error("DH_DEAD_LETTER_QUEUE_DH消费者异常", e);
            String errorMsg = e.getMessage();
            // 发送异常结果给常运智慧项目
//            HttpUti.postLzAbnormal(data, errorMsg, null);
        }
    }*/

    /**
     * 字节对象转换为字符串
     * @param object
     * @return
     */
    public String objToString(Object object){
        Message message = (Message) object;
        byte bytes[]=null;
        if (message != null) {
            bytes = message.getBody();
        }
        try {
            String msg = new String(bytes,"UTF-8");
            return msg;
        } catch (UnsupportedEncodingException e) {
            logger.error("字节对象转换为字符串异常：", e);
        }
        return null;
    }

    /**
     * 字符串转换为json对象
     * @param object
     * @return
     */
    public JSONObject objToJson(Object object){
        JSONObject json = new JSONObject();
        try {
            // 字节对象转换为字符串
            String str = objToString(object);
            // 判断是否为空、json格式
            if(StrUtil.isBlank(str) || !JSONUtil.isJson(str)){
                // 发送异常结果给常运智慧项目
                HttpUti.postLzAbnormal("Json格式不正确", null);
                return json;
            }
            json = JSONUtil.parseObj(str);
        } catch (Exception e){
            logger.error("转换JSON异常：", e);
        }
        return json;
    }

    /**
     * 判断json是否有值
     * @param object json数据
     * @return
     */
    public boolean isNullData(JSONObject object){
        if(object.isEmpty()){
            return true;
        }
        return false;
    }

    /**
     * 大豪设备 TRANSIENT操作
     * @param data 操作内容
     */
    public void DHExecute_TRANSIENT(JSONObject data){
        logger.info(data.toString() + "--------------");
        // 判断json是否有值
        if(isNullData(data)){
            return;
        }
        String code = data.getStr("code");
        String serialNumber = data.getStr("serialNumber");
        if(code.equals(cv.getDhOnline())){
            dhExecute.checkDeviceOnLineStatus(serialNumber, data);
        }else if(code.equals(cv.getOpenDoor())){
            dhExecute.openDoor(serialNumber, data);
        }
    }

    /**
     * 大豪设备 PERSISTENT操作
     * @param param 操作内容
     */
    public void DHExecute_PERSISTENT(JSONObject param){
        // 判断json是否有值
        if(isNullData(param)){
            return;
        }
        String code = param.getStr("code");
        String serialNumber = param.getStr("serialNumber");
        String adminPwd = param.getStr("adminPwd");

        if(code.equals(cv.getAddOpenDoorCard())){
            // 单张发卡
            dhExecute.serviceAddKey(serialNumber, adminPwd, param);
        }
        else if(code.equals(cv.getAddOpenDoorCardBatch())){
            String batchId = Convert.toStr(param.get("id"));
            String arrayData = JSONUtil.toJsonStr(param.get("data"));
            JSONArray array = JSONUtil.parseArray(arrayData);
            // 多张发卡到一个设备
            String[] strings = handleBatchCardData(serialNumber, array);
            if(strings != null){
                String key = serialNumber + "_" + batchId;
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("adminPwd", adminPwd);
                jsonObject.put("batchId", batchId);
                jsonObject.put("cardNos", strings[0]);
                jsonObject.put("cardStartDate", strings[1]);
                jsonObject.put("date", strings[2]);
                jsonObject.put("cardCount", array.size());
                JSONArray instructIds = new JSONArray();
                array.forEach(obj -> {
                    JSONObject cardData = JSONUtil.parseObj(obj);
                    instructIds.add(cardData.get("id"));
                });
                jsonObject.put("instructIds", instructIds);
                String jsonStr = JSONUtil.toJsonStr(jsonObject);
                this.redisTemplate.opsForHash().put(DH_CARD_BATCH_CACHE_NAME, key, jsonStr); //为失败下发做缓存，作为回调查询，以及失败后重新下发
                Response checkResult = dhExecute.checkDeviceOnLineStatus(serialNumber, new JSONObject());
                String resultData = JSONUtil.toJsonStr(checkResult.getData());
                if(!StringUtils.hasText(resultData)){
                    return;
                }
                String resultData2 = resultData.replaceAll("\\\\", "");
                JSONObject heartBeatJOSN = JSONUtil.parseObj(resultData2);
                Integer isOnline = (Integer) heartBeatJOSN.get("status");
                if(isOnline == 0){ //设备不在线，不发卡

                } else if(isOnline == 1) { //设备在线
                    dhExecute.addMoreKey(serialNumber, adminPwd, null, batchId, strings[0], 1, strings[1], strings[2], array.size());
                }
            }
        }
        else if(code.equals(cv.getDelOpenDoorCard())){
            // 删除卡
            dhExecute.delOpenDoorCard(serialNumber, adminPwd, param);
        }
        else if(code.equals(cv.getAddOpenDoorCardBatchAgain())){
            //重发卡
            this.handleAginAddMoreKey(serialNumber);
        }
        else if(code.equals(cv.getFormatData())){
            // 格式化，目前主要是删除设备上的卡号
            dhExecute.delOpenDoorCard(serialNumber, adminPwd, param);
        }
    }

    private void handleAginAddMoreKey(String serialNumber){
        //重发卡
        Map<Object, Object> entries = this.redisTemplate.opsForHash().entries(DH_CARD_BATCH_CACHE_NAME);
        if(entries == null){
            return;
        }
        int size = entries.size();
        if(size > 0){
            JSONObject push = null;
            Set<Object> objects = entries.keySet();
            for(Object o : objects){
                String key = (String)o;
                String[] s = key.split("_");
                if(serialNumber.equals(s[0])){
                    //重新下发卡片
                    JSONObject jsonObject = JSONUtil.parseObj(entries.get(key));
                    push = jsonObject;
                    break;
                }else{
                    continue;
                }
            }
            if(push != null){
                String batchId = (String)push.get("batchId");
                String cardNos = (String)push.get("cardNos");
                String cardStartDate = (String)push.get("cardStartDate");
                String date = (String)push.get("date");
                int cardCount = (int)push.get("cardCount");
                this.dhExecute.addMoreKey(serialNumber, (String)push.get("adminPwd"), null, batchId, cardNos, 1, cardStartDate, date, cardCount);
                JSONArray jsonArray = JSONUtil.parseArray(push.get("instructIds"));
                for(Object o : jsonArray){
                    String instructId = (String)o;
                    HttpUti.postCallback(instructId, "add_open_door_card", "1", "重发卡中", null);
                }
            }
        }
    }

    /**
     * 处理批量卡片指令数据
     * @param array
     * @return
     */
    private String[] handleBatchCardData(String serialNumber, JSONArray array){
        String[] strings = {"", "", ""};
        for(Object data : array){
            JSONObject instructData = JSONUtil.parseObj(data); //单张卡指令原数据
            JSONObject cardData =  JSONUtil.parseObj(instructData.get("data"));
            String cardNo = dhExecute.formatCardNo(cardData.getStr("cardNo"));
            if(StrUtil.isBlank(cardNo)){
                continue;
            }
            String sDate = cardData.getStr("beginDate");
            String eDate = cardData.getStr("endDate");
            Date startDate = DateUtil.parse(sDate);
            String startDateStr = DateUtil.format(startDate, "yyyyMMddHHmmss");
            Date endDate = DateUtil.parse(eDate);
            String endDateStr = DateUtil.format(endDate, "yyyyMMddHHmmss");
            strings[0] = strings[0] + cardNo;
            strings[1] = strings[1] + startDateStr;
            strings[2] = strings[2] + endDateStr;
        }
        return strings;
    }
}
