package tech.glinfo.enbao.modules.mq;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.reflect.TypeToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import tech.glinfo.enbao.common.utils.ByteUtils;
import tech.glinfo.enbao.common.utils.DateUtils;
import tech.glinfo.enbao.common.utils.RedisUtils;
import tech.glinfo.enbao.common.utils.StringUtils;
import tech.glinfo.enbao.modules.appuser.entity.AppUserEntity;
import tech.glinfo.enbao.modules.appuser.service.AppUserService;
import tech.glinfo.enbao.modules.sh.entity.*;
import tech.glinfo.enbao.modules.sh.form.ProtocolContent;
import tech.glinfo.enbao.modules.sh.service.*;

import java.util.*;


//智能锁
@Component("lockParse")
public class LockParse implements IParse {

    private final static Logger logger = LoggerFactory.getLogger(LockParse.class);

    @Autowired
    private OtherShDeviceService otherShDeviceService;

    @Autowired
    private OtherShDeviceRecordService otherShDeviceRecordService;

    @Autowired
    private ShDevicePasswordService shDevicePasswordService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private MqProducer mqProducer;

    @Autowired
    private TimeParseUtils timeParseUtils;

    @Autowired
    private AppUserService appUserService;

    @Autowired
    private OtherShDlinkService otherShDlinkService;

    @Override
    public Map<String, String> run(Object o, Map<String, String> datas) {
        ShDeviceEntity device = (ShDeviceEntity) o;
        Map<String, String> ws = new HashMap<>();

//        ws.put("deviceId", String.valueOf(device.getId()));
        if("91".equals(datas.get("cmd"))) {//登录包
            redisUtils.delete(datas.get("receiveId"));
        }
        else if("08".equals(datas.get("cmd"))) {//登录包

            redisUtils.set(datas.get("mac").toUpperCase(), datas.toString(), 180);//3分钟有效

            //校验设备时钟
            new Thread(new Runnable() {
                @Override
                public void run() {
                    logger.info("start checkDeviceTime");
                    timeParseUtils.checkDeviceTime1(datas.get("receiveId"), datas.get("content"), "06");
                }
            }).start();

            return datas;
        }else if("01".equals(datas.get("cmd"))) {//数据上报
            //数据上报
            //解析设备报文内容
            String content = datas.get("content");
//                String version = content.substring(0, 2);
            String eqh = content.substring(2, 4);
            String eq = String.valueOf(Integer.valueOf(eqh, 16));
            String actionh = content.substring(6, 8);
            Integer action = Integer.valueOf(actionh, 16);

            if (Integer.valueOf(eqh, 16) != 0) {
                //查询解析指令集
                List<ShInstructionParsingEntity> cmds = otherShDeviceService.getDeviceInstructionList(device.getProductId(), datas.get("cmd"));
                if (cmds != null && cmds.size() > 0) {
                    int length = 0;
                    //解析设备报文内容
                    String content1 = datas.get("content");
                    Map<String, Object> map = new HashMap<>();
                    for (ShInstructionParsingEntity cmd : cmds) {
                        String hex = content1.substring(length, length + cmd.getLength());
                        String hex1 = String.valueOf(Integer.valueOf(hex, 16));
                        map.put(cmd.getName(), hex1);
                        ws.put(cmd.getName(), hex1);
                        length += cmd.getLength();
                    }
                    otherShDeviceService.updateDeviceData(JSON.toJSONString(map), device.getId());
                }
            }

            String sqh = content.substring(34, 36);
            String sq = String.valueOf(Integer.valueOf(sqh, 16));
            //电池，放入websocket
//            ws.put("power", eq);
            ShDeviceRecordEntity entity = otherShDeviceRecordService.getOne(new QueryWrapper<ShDeviceRecordEntity>().eq("device_id", device.getId()).orderByDesc("id").last("LIMIT 1"));

            if(entity != null && entity.getRemark().equals(sq)) {
                logger.info("该开门记录已保存");
                return ws;
            }
            if (action != 0) {
                Integer id = Integer.parseInt(content.substring(10, 12), 16);
                //开锁记录
                ShDeviceRecordEntity recordEntity = new ShDeviceRecordEntity();
                recordEntity.setDeviceId(device.getId());
                recordEntity.setAction(action);
                recordEntity.setRemark(sq);
                recordEntity.setUserId(id);
                otherShDeviceRecordService.save(recordEntity);

                //场景检查
                sendCmd(device.getId());

            }else {
                logger.info("action为0");
            }
            redisUtils.delete(datas.get("receiveId")+"open");

        } else if("1F".equals(datas.get("cmd"))) {//远程开锁请求
            redisUtils.set(datas.get("receiveId")+":open", 1, 60);//30S有效
            ws.put("open", "1");

        } else if("1D".equals(datas.get("cmd")) && datas.get("content").equals("01")) {//查询动态密码/临时密码
            List<ShDevicePasswordEntity> pwds = new ArrayList<>(); //要下发的密码

            //临时密码
            List<ShDevicePasswordEntity> pwds1 = shDevicePasswordService.list(
                    new QueryWrapper<ShDevicePasswordEntity>().eq("device_id", device.getId()).eq("type", 2).eq("status", 1).orderByDesc("id").last("LIMIT 2"));
            //动态密码
            List<ShDevicePasswordEntity> pwds2 = shDevicePasswordService.list(
                    new QueryWrapper<ShDevicePasswordEntity>().eq("device_id", device.getId()).eq("type", 1).eq("status", 1).orderByDesc("id").last("LIMIT 2"));
            //临时密码ID
            List<Integer> ids1 = new ArrayList<>();
            //动态密码ID
            List<Integer> ids2 = new ArrayList<>();

            //如果临时密码小于两条，取出之前没有过期的密码凑够两条
            if (pwds1 != null  && pwds1.size() > 0) {
                if (pwds1.size() < 2) {
                    List<ShDevicePasswordEntity> list = redisUtils.get("lockpwd1" + device.getId(), new TypeToken<List<ShDevicePasswordEntity>>() {
                    }.getType());
                    if (list != null) {
                        list.sort((o1, o2) -> {
                            if (o1.getId() < o2.getId()) {
                                return 1;
                            }
                            if (o1.getId().equals(o2.getId())) {
                                return 0;
                            }
                            return -1;
                        });

                        for (ShDevicePasswordEntity entity : list) {
                            boolean flag = true;
                            for (ShDevicePasswordEntity passwordEntity : pwds1) {
                                if (passwordEntity.getId().equals(entity.getId()) || entity.getExpiredTime().getTime() < new Date().getTime()) {
                                    flag = false;
                                    break;
                                }
                            }
                            if (flag) {
                                pwds1.add(entity);
                            }
                            if (pwds1.size() == 2) {
                                break;
                            }
                        }
                    }

                }

                pwds.addAll(pwds1);
                for (ShDevicePasswordEntity entity : pwds1) {
                    ids1.add(entity.getId());
                }
                redisUtils.set("lockpwd1" + device.getId(), pwds1);
            }
            Date date = new Date();
            if (pwds2 != null  && pwds2.size() > 0) {
                if (pwds2.size() < 2) {
                    List<ShDevicePasswordEntity> list = redisUtils.get("lockpwd2" + device.getId(), new TypeToken<List<ShDevicePasswordEntity>>() {
                    }.getType());
                    if (list != null) {
                        list.sort((o1, o2) -> {
                            if (o1.getId() < o2.getId()) {
                                return 1;
                            }
                            if (o1.getId().equals(o2.getId())) {
                                return 0;
                            }
                            return -1;
                        });
                        for (ShDevicePasswordEntity entity : list) {
                            boolean flag = true;
                            for (ShDevicePasswordEntity passwordEntity : pwds2) {
                                if (passwordEntity.getId().equals(entity.getId()) || entity.getExpiredTime().getTime() < new Date().getTime()) {
                                    flag = false;
                                    break;
                                }
                            }
                            if (flag) {
                                pwds2.add(entity);
                            }
                            if (pwds2.size() == 2) {
                                break;
                            }
                        }
                    }

                }
                pwds.addAll(pwds2);
                for (ShDevicePasswordEntity entity : pwds2) {
                    entity.setExpiredTime(DateUtils.addDateMinutes(date, 5));
                    ids2.add(entity.getId());
                }
                redisUtils.set("lockpwd2" + device.getId(), pwds2);
            }
            List<ShDevicePasswordEntity> pwds3 = new ArrayList<>();
            if(pwds.size() > 0) {
                ProtocolContent protocol = new ProtocolContent();
                protocol.setCmd("1D");
                protocol.setDeviceType("06");
                protocol.setReceiveId(device.getNumbering());
                StringBuilder sb = new StringBuilder(ByteUtils.int2Hex(pwds.size()));
                String dExpiredTime = null;
                //已下发密码
//                StringBuilder dpwd = new StringBuilder();
                for (ShDevicePasswordEntity entity : pwds) {

                    pwds3.add(entity);
//                    ids.add(entity.getId());
                    sb.append(ByteUtils.int2Hex(entity.getType()));
                    if(entity.getType()==1) {//动态密码下发当前时间
                        //5分钟有效
                        if(dExpiredTime == null) {//保证同时下发的有效期一样
                            dExpiredTime = DateUtils.getHexByDate(DateUtils.addDateMinutes(date, 5));
                        }
                        sb.append(dExpiredTime);
                        entity.setExpiredTime(DateUtils.addDateMinutes(date, 5));
                        shDevicePasswordService.updateById(entity);

                    } else {
                        sb.append(DateUtils.getHexByDate(entity.getExpiredTime()));
                    }
                    sb.append(ByteUtils.strToHex(entity.getPassword()));
                    /*if(entity.getType() == 1) {
                        dpwd.append(entity.getPassword());
                    }*/
                }
                protocol.setContent(sb.toString());
                //下发给MQ，IoT接收到MQ消息会下发给设备
                mqProducer.sendT(JSON.toJSONString(protocol));


                redisUtils.set("lockpwd" + device.getId(), pwds3);
                ShDevicePasswordEntity one = new ShDevicePasswordEntity();
                one.setStatus(3);
                if (ids1.size() > 0) {
                    shDevicePasswordService.update(one, new QueryWrapper<ShDevicePasswordEntity>().eq("device_id", device.getId()).eq("type", 2).notIn("id", ids1));
                }
                if (ids2.size() > 0) {
                    shDevicePasswordService.update(one, new QueryWrapper<ShDevicePasswordEntity>().eq("device_id", device.getId()).eq("type", 1).notIn("id", ids2));
                }
            }

//            return null;
        }else if("1D".equals(datas.get("cmd")) && datas.get("content").equals("00")) {
            List<ShDevicePasswordEntity> list = redisUtils.get("lockpwd" + device.getId(), new TypeToken<List<ShDevicePasswordEntity>>() {
            }.getType());

            //已下发密码
            StringBuilder dpwd = new StringBuilder();
            for (ShDevicePasswordEntity entity : list) {
                if(entity.getType() == 1) {
                    dpwd.append(entity.getPassword());
                }
                ShDevicePasswordEntity one = new ShDevicePasswordEntity();
                one.setId(entity.getId());
                one.setStatus(2);
                shDevicePasswordService.updateById(one);
            }
            if(dpwd.length() > 0) {
                ws.put("dpwd", dpwd.toString());
            }
            redisUtils.delete("lockpwd" + device.getId());
        }else if("21".equals(datas.get("cmd"))) {//上报试错告警
            String content = datas.get("content");
            logger.info("上报试错告警" + content);
            int action = Integer.parseInt(content.substring(4, 6), 16);
            AppUserEntity userEntity = appUserService.getById(device.getUserId());
            String tishi = action == 1 ? "指纹" : action == 2 ? "密码" : action == 3 ? "卡片" : action == 20 ? "人脸" : action == 21 ? "掌纹" : "未知";
            if (StringUtils.isNotBlank(userEntity.getThirdId())) {
                mqProducer.sendPush(tishi + "多次开锁失败提示", "设备: " + device.getNumbering() + " " + tishi + "多次开锁失败提示", userEntity.getThirdId());
            }
        }

        //处理设备期限使用标志
        /*new Thread(new Runnable() {
            @Override
            public void run() {
                logger.info("start handleEndTime");
                timeParseUtils.handleEndTime(device.getId(), "06", device.getNumbering(), datas.get("cmd"));
            }
        }).start();*/

        return ws;
    }

    private void sendCmd(Integer id) {
        String sss = DateUtils.format(new Date(), "yyyy-MM-dd HH:mm");
        ShDlinkEntity dlinkEntity = otherShDlinkService.checkTime(sss.substring(sss.length()-5), id);
        if (dlinkEntity != null) {
            String key = "device:dlink:" + dlinkEntity.getStart() + "-" + dlinkEntity.getEnd() + ":" + dlinkEntity.getDeviceId();
            String json = redisUtils.get(key);
            logger.info("场景找到1" + json);
            if (StringUtils.isNotBlank(json)) {
                for (String s : json.split("-")) {
                    logger.info("场景找到2" + s);
                    mqProducer.sendT(s);
                }
            }
        }
    }


}
