package com.mortals.xhx.busiz.web;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.annotation.UnAuth;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.service.IAuthTokenService;
import com.mortals.framework.util.AESUtil;
import com.mortals.framework.util.DateUtils;
import com.mortals.xhx.base.framework.annotation.ApiUserAuth;
import com.mortals.xhx.base.login.web.LoginForm;
import com.mortals.xhx.base.system.user.model.UserEntity;
import com.mortals.xhx.base.system.user.service.UserService;
import com.mortals.xhx.busiz.req.DeviceMsgReq;
import com.mortals.xhx.busiz.req.DeviceReq;
import com.mortals.xhx.busiz.req.UploadDeviceReq;
import com.mortals.xhx.busiz.rsp.*;
import com.mortals.xhx.common.code.*;
import com.mortals.xhx.common.key.Constant;
import com.mortals.xhx.common.model.DefaultTbQueueMsgHeaders;
import com.mortals.xhx.common.model.MessageHeader;
import com.mortals.xhx.common.utils.BeanUtil;
import com.mortals.xhx.common.utils.DownMsgTask;
import com.mortals.xhx.common.utils.EncryptUtil;
import com.mortals.xhx.common.utils.SendTaskThreadPool;
import com.mortals.xhx.module.device.model.DeviceEntity;
import com.mortals.xhx.module.device.service.DeviceService;
import com.mortals.xhx.module.platform.model.PlatformEntity;
import com.mortals.xhx.module.platform.model.PlatformQuery;
import com.mortals.xhx.module.platform.service.PlatformService;
import com.mortals.xhx.module.product.model.ProductEntity;
import com.mortals.xhx.module.product.model.ProductQuery;
import com.mortals.xhx.module.product.service.ProductService;
import com.mortals.xhx.queue.TbQueueMsgHeaders;
import com.mortals.xhx.queue.TopicPartitionInfo;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static com.mortals.xhx.common.key.Constant.DES_STR;
import static com.mortals.xhx.common.key.Constant.ENCRYPT_STR;

/**
 * 设备
 *
 * @author: zxfei
 * @date: 2021/8/24 20:28
 */
@RestController
@Slf4j
@RequestMapping("/api")
public class DeviceApiController {
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private ProductService productService;
    @Autowired
    private UserService userService;
    @Autowired
    private IAuthTokenService authTokenService;
    @Autowired
    private PlatformService platformService;
    @Value("${queue.rabbitmq.virtual_host:}")
    private String virtualHost;
    @Value("${queue.rabbitmq.password:}")
    private String password;
    @Value("${queue.rabbitmq.host:}")
    private String host;
    @Value("${queue.rabbitmq.port:}")
    private int port;
    @Value("${queue.rabbitmq.username:}")
    private String username;
    @Value("${queue.rabbitmq.queue-properties.x-message-ttl:86400000}")
    private String messageTtl;
    @Value("${token.secret}")
    private String secret;
    @Autowired
    private SendTaskThreadPool sendTaskThreadPool;

    /**
     * 设备注册
     *
     * @param req
     * @return
     */
    @PostMapping("register")
    public String register(@RequestBody DeviceReq req) {
        log.info("【设备注册】【请求体】-->  " + JSONObject.toJSONString(req));
        ApiResp<DeviceResp> rsp = new ApiResp<>();
        rsp.setCode(ApiRespCodeEnum.SUCCESS.getValue());
        DeviceResp deviceResp = new DeviceResp();
        try {
            DeviceEntity deviceEntity = checkDeviceExist(req);
            if (deviceEntity.getActive() != ActiveEnum.已激活.getValue()) {
                throw new AppException("当前设备未激活，请在后台配置后再激活！");
            }
            if (deviceEntity.getStatus() != StatusEnum.启用.getValue()) {
                throw new AppException("当前设备未启用，请在后台启用当前设备！");
            }

            DeviceQueueAuthInfo authInfo = new DeviceQueueAuthInfo();
            authInfo.setHost(host);
            authInfo.setPort(port);
            authInfo.setUsername(username);
            authInfo.setPassword(password);
            authInfo.setMessageTtl(messageTtl);
            authInfo.setVirtualHost(virtualHost);
            PlatformEntity platformEntity = platformService.get(deviceEntity.getPlatformId());
            if (ObjectUtils.isEmpty(platformEntity)) {
                throw new AppException("当前设备未配置所属系统平台，请在后台配置后再激活！");
            }

            ProductEntity productEntity = productService.get(deviceEntity.getProductId());
            if (ObjectUtils.isEmpty(productEntity)) {
                throw new AppException("当前设备未配置所属产品，请在后台配置后再激活！");
            }
            authInfo.setExchangeName(platformEntity.getPlatformSn() + Constant.EXCHANGE_SPLIT + productEntity.getProductCode());
            authInfo.setUploadTopicFilter(Constant.UPLOAD_TOPIC + deviceEntity.getDeviceCode());
            authInfo.setDownTopicFilter(Constant.DOWN_TOPIC + deviceEntity.getDeviceCode());
            authInfo.setHomeUrl(platformEntity.getHomeUrl());

           // String content = AESUtil.encryptForApp(JSON.toJSONString(authInfo), secret);

            String content = EncryptUtil.myEnscrt(JSON.toJSONString(authInfo), 9, DES_STR, ENCRYPT_STR);


            deviceResp.setContent(content);
            deviceEntity.setOnlineTime(new Date());
            deviceEntity.setDeviceOnlineStatus(DeviceOnlineStatusEnum.在线.getValue());
            deviceService.update(deviceEntity);
            rsp.setData(deviceResp);
        } catch (Exception e) {
            log.error("接收数据失败", e);
            rsp.setCode(ApiRespCodeEnum.FAILED.getValue());
            rsp.setMsg(e.getMessage());
            return JSON.toJSONString(rsp);
        }
        log.info("响应【设备注册】【响应体】-->  " + JSONObject.toJSONString(rsp));
        return JSON.toJSONString(rsp);
    }

    /**
     * 获取Token
     *
     * @return
     */
    @PostMapping("getToken")
    public String getToken(@RequestBody LoginForm loginForm) {
        ApiResp<String> rsp = new ApiResp<>();
        rsp.setCode(ApiRespCodeEnum.SUCCESS.getValue());
        try {
            UserEntity userEntity = userService.doLogin(loginForm.getLoginName(), loginForm.getPassword(), "");
            if (!ObjectUtils.isEmpty(userEntity)) {
                this.authTokenService.setUser(userEntity);
                userEntity.setExpireTime(DateUtils.addCurrDate(7).getTime());
                userEntity.setToken(IdUtil.fastSimpleUUID());
                String token = authTokenService.createToken(userEntity);
                rsp.setData(token);
            }
        } catch (Exception e) {
            log.error("异常", e);
            rsp.setCode(ApiRespCodeEnum.FAILED.getValue());
            rsp.setMsg(e.getMessage());
            return JSON.toJSONString(rsp);
        }
        log.info("响应【获取Token】【响应体】--> {}", JSONObject.toJSONString(rsp));
        return JSON.toJSONString(rsp);
    }

    /**
     * 获取平台与产品
     *
     * @return
     */
    @GetMapping("getPlatformAndProduct")
    public String getPlatformAndProduct() {
        ApiResp<PlatformAndProductResp> rsp = new ApiResp<>();
        rsp.setCode(ApiRespCodeEnum.SUCCESS.getValue());
        PlatformAndProductResp platformAndProductResp = new PlatformAndProductResp();
        try {
            List<PlatformInfo> platformInfoList = platformService.find(new PlatformQuery()).stream().map(item -> {
                PlatformInfo platformInfo = new PlatformInfo();
                BeanUtils.copyProperties(item, platformInfo, BeanUtil.getNullPropertyNames(item));
                return platformInfo;
            }).collect(Collectors.toList());
            platformAndProductResp.setPlatformList(platformInfoList);
            List<ProductInfo> productInfoList = productService.find(new ProductQuery()).stream().map(item -> {
                ProductInfo productInfo = new ProductInfo();
                BeanUtils.copyProperties(item, productInfo, BeanUtil.getNullPropertyNames(item));
                return productInfo;
            }).collect(Collectors.toList());
            platformAndProductResp.setProductList(productInfoList);

            rsp.setData(platformAndProductResp);
        } catch (Exception e) {
            log.error("异常", e);
            rsp.setCode(ApiRespCodeEnum.FAILED.getValue());
            rsp.setMsg(e.getMessage());
            return JSON.toJSONString(rsp);
        }
        log.info("响应【获取平台与产品】【响应体】--> {}", JSONObject.toJSONString(rsp));
        return JSON.toJSONString(rsp);
    }


    /**
     * 设备数据上报
     *
     * @param list
     * @return
     */
    @PostMapping("callback")
    @UnAuth
    public String callback(@RequestBody List<DeviceMsgReq> list) {
        log.info("【设备数据消息接收】【请求体】-->  " + JSONObject.toJSONString(list));
        ApiResp<String> rsp = new ApiResp<>();
        rsp.setMsg(ApiRespCodeEnum.SUCCESS.getLabel());
        rsp.setCode(ApiRespCodeEnum.SUCCESS.getValue());
        try {
            DownMsgTask downMsgTask = new DownMsgTask(list, platformService, productService, deviceService);
            sendTaskThreadPool.execute(downMsgTask);
        } catch (Exception e) {
            log.error("接收数据失败", e);
            rsp.setCode(ApiRespCodeEnum.FAILED.getValue());
            rsp.setMsg(e.getMessage());
            return JSON.toJSONString(rsp);
        }

        log.debug("响应【设备数据消息接收】【响应体】-->  " + JSONObject.toJSONString(rsp));
        return JSON.toJSONString(rsp);
    }


    /**
     * 设备数据上报
     *
     * @param req
     * @return
     */
    @PostMapping("upload")
    //@DeviceAuth
    public String upload(@RequestBody UploadDeviceReq req) {
        log.info("【设备数据上报】【请求体】-->  " + JSONObject.toJSONString(req));
        ApiResp<String> rsp = new ApiResp<>();
        rsp.setMsg(ApiRespCodeEnum.SUCCESS.getLabel());
        rsp.setCode(ApiRespCodeEnum.SUCCESS.getValue());
        try {
            //根据设备编码查询设备
            DeviceEntity deviceEntity = deviceService.getExtCache(req.getDeviceCode());
            if (!ObjectUtils.isEmpty(deviceEntity)) {
                //将上报信息转发到mq中

                PlatformEntity platformEntity = platformService.get(deviceEntity.getPlatformId());
                if (ObjectUtils.isEmpty(platformEntity)) {
                    throw new AppException("当前设备未配置所属系统平台，请在后台配置后再激活！");
                }
                // authInfo.setHost(platformEntity.getPlatformSn());
                ProductEntity productEntity = productService.get(deviceEntity.getProductId());
                if (ObjectUtils.isEmpty(productEntity)) {
                    throw new AppException("当前设备未配置所属产品，请在后台配置后再激活！");
                }
                String exchangeName = platformEntity.getPlatformSn() + Constant.EXCHANGE_SPLIT + productEntity.getProductCode();

                TopicPartitionInfo info = TopicPartitionInfo.builder().exchangeName(exchangeName).topic(Constant.UPLOAD_TOPIC + deviceEntity.getDeviceMac()).build();
                TbQueueMsgHeaders header = new DefaultTbQueueMsgHeaders();
                header.put(MessageHeader.MESSAGETYPE, Constant.MESSAGETYPE_HEARTBEAT);
                for (int i = 0; i < 1000; i++) {
                    deviceService.sendDeviceMessage(deviceEntity, info, header, JSON.toJSONString(req), null);
                    // Thread.sleep(50);
                }
                //log.info(String.format("sendMsgResp:%s", JSON.toJSONString(sendDeviceMessageResp)));
            }
        } catch (Exception e) {
            log.error("接收数据失败", e);
            rsp.setCode(ApiRespCodeEnum.FAILED.getValue());
            rsp.setMsg(e.getMessage());
            return JSON.toJSONString(rsp);
        }

        log.debug("响应【设备数据上报】【响应体】-->  " + JSONObject.toJSONString(rsp));
        return JSON.toJSONString(rsp);
    }


    /**
     * 设备对外接收接口
     *
     * @param req
     * @return
     */
    @PostMapping("receive")
    @ApiUserAuth
    public String receive(@RequestBody DeviceReq req) {
        log.info("【设备接收】【请求体】-->  " + JSONObject.toJSONString(req));
        ApiResp<String> rsp = new ApiResp<>();
        rsp.setMsg(ApiRespCodeEnum.SUCCESS.getLabel());
        rsp.setCode(ApiRespCodeEnum.SUCCESS.getValue());
        try {
            switch (DeviceStatusEnum.getByValue(req.getReceiveMethod())) {
                case ADD:
                    deviceAdd(req);
                    break;
                case UPDATE:
                    deviceUpdate(req);
                    break;
                case DEL:
                    deviceDel(req);
                    break;
                case ACTIVE:
                    deviceActive(req);
                    break;
                case ENABLED:
                    deviceEnabled(req);
                    break;
                case STOP:
                    deviceStop(req);
                    break;
            }
        } catch (Exception e) {
            log.error("接收数据失败", e);
            rsp.setCode(ApiRespCodeEnum.FAILED.getValue());
            rsp.setMsg(e.getMessage());
            return JSON.toJSONString(rsp);
        }
        log.info("响应【设备接收】【响应体】-->  " + JSONObject.toJSONString(rsp));
        return JSON.toJSONString(rsp);
    }


    private void deviceAdd(DeviceReq req) throws AppException {
        log.info("【设备新增】【请求体】-->  " + JSONObject.toJSONString(req));
        //根据设备编码查询设备
        DeviceEntity deviceEntity = deviceService.getExtCache(req.getDeviceCode());
        if (!ObjectUtils.isEmpty(deviceEntity)) {
            throw new AppException("当前设备编码已存在！");
        }
        if (ObjectUtils.isEmpty(req.getPlatformCode())) {
            throw new AppException("当前平台编码为空！");
        }
        PlatformEntity platformEntity = platformService.selectOne(new PlatformQuery().platformSn(req.getPlatformCode()));
        if (ObjectUtils.isEmpty(platformEntity)) {
            throw new AppException("所属系统平台不存在！");
        }

        ProductEntity productEntity = productService.selectOne(new ProductQuery().productCode(req.getProductCode()));
        if (ObjectUtils.isEmpty(productEntity)) {
            throw new AppException("所属产品编码不存在");
        }
        deviceEntity = new DeviceEntity();
        deviceEntity.initAttrValue();
        deviceEntity.setDeviceName(req.getDeviceName());
        deviceEntity.setDeviceCode(req.getDeviceCode());
        deviceEntity.setDeviceMac(req.getDeviceCode());
        deviceEntity.setSiteId(req.getSiteId());
        deviceEntity.setSiteCode(req.getSiteCode());
        deviceEntity.setSiteName(req.getSiteName());
        deviceEntity.setPlatformId(platformEntity.getId());
        deviceEntity.setPlatformName(platformEntity.getPlatformName());
        deviceEntity.setProductId(productEntity.getId());
        deviceEntity.setProductName(productEntity.getProductName());
        deviceEntity.setIp(req.getIp());
        deviceEntity.setCenternum(req.getCenternum());
        deviceEntity.setPort(req.getPort());
        deviceEntity.setDeviceRemark(req.getDeviceRemark());
        deviceEntity.setCreateUserId(1L);
        deviceEntity.setCreateTime(new Date());
        deviceEntity.setSwitchSend(false);
        deviceService.save(deviceEntity);

    }

    private void deviceUpdate(DeviceReq req) throws AppException {
        log.info("【设备更新】【请求体】-->  " + JSONObject.toJSONString(req));
        //根据设备编码查询设备
        DeviceEntity deviceEntity = deviceService.getExtCache(req.getDeviceCode());

        if (ObjectUtils.isEmpty(deviceEntity)) {
            throw new AppException("当前设备编码不存在！");
        }

        if (ObjectUtils.isEmpty(req.getPlatformCode())) {
            throw new AppException("当前平台编码为空！");
        }

        PlatformEntity platformEntity = platformService.selectOne(new PlatformQuery().platformSn(req.getPlatformCode()));
        if (ObjectUtils.isEmpty(platformEntity)) {
            throw new AppException("所属系统平台不存在！");
        }
        if (ObjectUtils.isEmpty(req.getPlatformCode())) {
            throw new AppException("当前产品Code为空！");
        }
        ProductEntity productEntity = productService.selectOne(new ProductQuery().productCode(req.getProductCode()));
        if (ObjectUtils.isEmpty(productEntity)) {
            throw new AppException("所属产品编码不存在");
        }

        deviceEntity.setDeviceName(req.getDeviceName());
        deviceEntity.setDeviceCode(req.getDeviceCode());
        deviceEntity.setDeviceMac(req.getDeviceCode());
        deviceEntity.setSiteId(req.getSiteId());
        deviceEntity.setSiteCode(req.getSiteCode());
        deviceEntity.setSiteName(req.getSiteName());
        deviceEntity.setPlatformId(platformEntity.getId());
        deviceEntity.setPlatformName(platformEntity.getPlatformName());
        deviceEntity.setProductId(productEntity.getId());
        deviceEntity.setProductName(productEntity.getProductName());
        deviceEntity.setIp(req.getIp());
        deviceEntity.setCenternum(req.getCenternum());
        deviceEntity.setPort(req.getPort());
        deviceEntity.setDeviceRemark(req.getDeviceRemark());
        deviceEntity.setUpdateUserId(1L);
        deviceEntity.setUpdateTime(new Date());
        deviceEntity.setSwitchSend(false);
        deviceService.save(deviceEntity);

    }

    private void deviceDel(DeviceReq req) throws AppException {
        log.info("【设备删除】【请求体】-->  " + JSONObject.toJSONString(req));
        //根据设备编码查询设备
        DeviceEntity deviceEntity = checkDeviceExist(req);
        deviceService.remove(deviceEntity.getId(), null);

    }

    private void deviceActive(DeviceReq req) throws AppException {
        log.info("【设备激活】【请求体】-->  " + JSONObject.toJSONString(req));
        //根据设备编码查询设备
        DeviceEntity deviceEntity = checkDeviceExist(req);
        if (deviceEntity.getActive() == ActiveEnum.已激活.getValue()) {
            throw new AppException("当前设备已激活！");
        }
        deviceEntity.setActive(ActiveEnum.已激活.getValue());
        deviceEntity.setUpdateTime(new Date());
        deviceEntity.setUpdateUserId(1L);
        deviceEntity.setSwitchSend(false);
        deviceService.update(deviceEntity);

    }

    private void deviceEnabled(DeviceReq req) throws AppException {
        log.info("【设备启用】【请求体】-->  " + JSONObject.toJSONString(req));
        //根据设备编码查询设备
        DeviceEntity deviceEntity = checkDeviceExist(req);
        deviceEntity.setActive(YesNoEnum.YES.getValue());
        deviceEntity.setUpdateTime(new Date());
        deviceEntity.setUpdateUserId(1L);
        deviceEntity.setSwitchSend(false);
        deviceService.update(deviceEntity);
    }

    private void deviceStop(DeviceReq req) throws AppException {
        log.info("【设备停用】【请求体】-->  " + JSONObject.toJSONString(req));
        DeviceEntity deviceEntity = checkDeviceExist(req);
        deviceEntity.setActive(YesNoEnum.YES.getValue());
        deviceEntity.setUpdateTime(new Date());
        deviceEntity.setUpdateUserId(1L);
        deviceEntity.setSwitchSend(false);
        deviceService.update(deviceEntity);
    }

    private DeviceEntity checkDeviceExist(DeviceReq req) {
        if (ObjectUtils.isEmpty(req.getDeviceCode())) {
            throw new AppException("当前设备编码不存在！");
        }
        DeviceEntity deviceEntity = deviceService.getExtCache(req.getDeviceCode());
        if (ObjectUtils.isEmpty(deviceEntity)) {
            //初始化新增基础设备，后续在线完善信息后再行注册添加
            deviceEntity = new DeviceEntity();
            deviceEntity.initAttrValue();
            deviceEntity.setDeviceMac(req.getDeviceCode());
            deviceEntity.setDeviceCode(req.getDeviceCode());
            deviceEntity.setCreateTime(new Date());
            deviceEntity.setCreateUserId(1L);
            deviceService.getDeviceDao().insert(deviceEntity);

        }
        return deviceEntity;
    }
}
