package com.sptg.repeater.controller;

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.dh.PageData;
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.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.async.DeferredResult;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 大豪设备回调信息处理
 * @author yb
 * @date 2020-04-21
 */
@RestController
public class DHCallbackController implements ServletContextAware {

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

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

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    private CommonValues cv;

    private ServletContext servletContext;

    // Spring这里是通过实现ServletContextAware接口来注入ServletContext对象
    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    public HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
    }

    public PageData getPageData() {
        return new PageData(this.getRequest());
    }

    @ResponseBody
    @RequestMapping(value = "/dh/callBackListener")
    public DeferredResult<Object> callBackListener(HttpServletRequest request,
                                                   HttpServletResponse response) throws Exception {
        try {
            Map<String, Object> map = new HashMap<String, Object>();
            final DeferredResult<Object> deferredResult = new DeferredResult<Object>();
            PageData pd = this.getPageData();
            logger.info("大豪回调进来了");
            String PARAMS = pd.getString("PARAMS").toString();
            logger.info(PARAMS+"========大豪回调结果");
            try {
                callBackProcessing(PARAMS);
            }catch (Exception e){
                map.put("msg", "ok");
                map.put("result", "0");
                map.put("data", "receive msg.");
                deferredResult.setResult(map);
                return deferredResult;
            }
            map.put("msg", "ok");
            map.put("result", "0");
            map.put("data", "receive msg.");
            deferredResult.setResult(map);
            return deferredResult;
        } catch (Exception e){
            logger.error("大豪回调结果异常：", e);
        }
        return null;
    }

    @PostMapping(value = "/testDHCallBack")
    public String testDHCallBack(String json){
        callBackProcessing(json);
        return "testDHCallBack";
    }

    /**
     * 回调结果处理
     * @param jsonStr
     */
    public void callBackProcessing(String jsonStr){
        try {
            JSONObject data = JSONUtil.parseObj(jsonStr);
            String operate = data.getStr("OPERATE");

            String code = "";

            switch (operate) {
                case "1B":
                    code = cv.getOpenDoor();
                    break;
                case "27":
                    code = cv.getAddOpenDoorCard();
                    break;
                case "28":
                    code = cv.getDelOpenDoorCard();
                    break;
                case "AB":
                    code = cv.getAddOpenDoorCard();
                    break;
                case "AC":
                    code = cv.getAddOpenDoorCard();
                    break;
                case "40":
                    code = cv.getOpenDoorLog();
                    break;
                case "01":
                    code = cv.getHeartbeat();
                    break;
                default:
                    break;
            }

            String id = (String)data.get("SERIALNO");
            String serialNo = null;
            String serialNumber = null;
            JSONArray array = JSONUtil.parseArray(data.get("PARAMS"));
            String success = (String)array.get(1);
            String status = "2";
            String errorMsg = "ok";
            if(!success.equals("00")){
                status = "3";
                errorMsg = "设备指令接收成功，但设备处理失败";
            }
            if(code.equals(cv.getAddOpenDoorCard()) && operate.equals("AC")){
                logger.info(jsonStr+"========大豪回调结果");
                if(null != data.get("SERIALNO")){
                    serialNo = (String)data.get("SERIALNO");
                    serialNumber = (String)data.get("DEVICEID");
                }
                String key = serialNumber + "_" + serialNo;
                Object o = this.redisTemplate.opsForHash().get(DH_CARD_BATCH_CACHE_NAME, key);
                if(o != null){
                    JSONObject jsonObject = JSONUtil.parseObj(o);
                    JSONArray jsonArray = JSONUtil.parseArray(jsonObject.get("instructIds"));
                    for(Object obj : jsonArray){
                        String instructId = (String)obj;
                        if(StringUtils.hasText(instructId)){
                            HttpUti.postCallback(instructId, code, status, errorMsg, data);
                        }
                    }
                    redisTemplate.opsForHash().delete(DH_CARD_BATCH_CACHE_NAME, key);
                    redisTemplate.delete(key);
                }else{
                    HttpUti.postCallback(serialNo, code, status, errorMsg, data);
                }
            }else if(code.equals(cv.getOpenDoorLog())){
                logger.info(jsonStr+"========大豪回调结果");
                //调用常运智慧项目开门记录接口
                HttpUti.postLzAbnormalUploadDoorLog(data);
                HttpUti.postCallback(id, code, status, errorMsg, data);
            }else if(code.equals(cv.getOpenDoor())){
                //调用常运智慧项目远程开门记录接口
                HttpUti.postLzAbnormalUploadOpenDoor(data);
                id = id.split("=")[0];
                HttpUti.postCallback(id, code, status, errorMsg, data);
            }else if(code.equals(cv.getHeartbeat())){
                logger.info("心跳原型：" + jsonStr+"========大豪回调结果");
                //调用常运智慧项目心跳上传记录接口
                HttpUti.postLzAbnormalCheckHeartBeat(data);
                Map<Object, Object> entries = this.redisTemplate.opsForHash().entries(DH_CARD_BATCH_CACHE_NAME);
                if(entries == null || entries.size() <= 0){
                    return;
                }else{
                    serialNumber = (String)data.get("DEVICEID");
                    Set<Object> objects = entries.keySet();
                    for (Object o : objects){
                        String key = (String)o;
                        String[] s = key.split("_");
                        if(serialNumber.equals(s[0])){
                            String s1 = this.redisTemplate.opsForValue().get(key);
                            if(!StringUtils.hasText(s1)){ //没有重发过，就下发一个重发指令到队列
                                JSONObject jsonObject = new JSONObject();
                                jsonObject.put("code", cv.getAddOpenDoorCardBatchAgain());
                                jsonObject.put("serialNumber", serialNumber);
                                this.redisTemplate.opsForValue().set(key, key + " had resent");
                                this.redisTemplate.expire(key, 180, TimeUnit.SECONDS); //3分钟后自动消失
                                rabbitTemplate.convertAndSend("PERSISTENT_EXCHANGE_DH","dh." + cv.getAddOpenDoorCardBatchAgain(), jsonObject.toString());
                            }
                            break;
                        }else{
                            continue;
                        }
                    }
                }
            }else{
                HttpUti.postCallback(id, code, status, errorMsg, data);
            }
        } catch (Exception e) {
            logger.error("大豪回调处理异常：", e);
        }
    }

    // 大豪回调信息
    // {"DEVICEID":"AEAC082E","RESULT":0,"OPERATE":"1B","PARAMS":["AEAC082E","00","64"]}============开锁
    // {"DEVICEID":"AEAC082E","RESULT":0,"OPERATE":"01","PARAMS":["AEAC082E","00","07","00","0","0","69"]}============心跳

    // 执行大豪接口返回的信息
    // 远程开门
    // {"msg":"msg has sent","result":0,"data":""} 开门成功
    // {"msg":"msg has sent","result":0,"data":""} 开门失败
    // 回调结果
    // {"DEVICEID":"AEAC082E","RESULT":0,"OPERATE":"1B","PARAMS":["AEAC082E","00","64"]}
    // {"DEVICEID":"AEAC082E","RESULT":0,"OPERATE":"1B","SERIALNO":"98986554","PARAMS":["AEAC082E","00","64"]}

    // 是否在线
    // {"msg":"DEVICELOCK_STATUS(1:onLine 0:notOnLine) : 1","result":0,"data":{"DEVICEID":"AEAC082E","CMD":"01","status":1}}

    // 多张发卡（IMPORTFLAG=1）
    // 回调结果
    // {"DEVICEID":"CD329D84","RESULT":0,"OPERATE":"27","SERIALNO":"1163664108063813634","PARAMS":["CD329D84","00"]}
    // {"DEVICEID":"CD329D84","RESULT":0,"OPERATE":"AB","SERIALNO":"1163664108063813634","PARAMS":["CD329D84","00","00e0d06c"]}
    // {"DEVICEID":"CD329D84","RESULT":0,"OPERATE":"AC","SERIALNO":"1163664108063813634","PARAMS":["CD329D84","00"]}

    // 单张发卡（IMPORTFLAG=0）
    // 回调结果
    // {"DEVICEID":"CD329D84","RESULT":0,"OPERATE":"27","SERIALNO":"1163664108063813634","PARAMS":["CD329D84","00"]}
    // {"DEVICEID":"CD329D84","RESULT":0,"OPERATE":"AC","SERIALNO":"1163664108063813634","PARAMS":["CD329D84","00"]}

    // 删除卡
    // 回调结果
    // {"DEVICEID":"CD329D84","RESULT":0,"OPERATE":"28","PARAMS":["CD329D84","00"]}

    // 开锁记录
    // 回调结果
    // {"DEVICEID":"CD329D84","RESULT":1,"OPERATE":"40","PARAMS":["CD329D84","1","3","00E0D06CFFFFFFFF","1","2020-04-27 09:07:00"]}
    //                                                             设备ID ：记录条数：类型：卡片id：操作方式(1->开锁) ：操作时间
}
