package com.mortals.xhx.module.device.service.impl;

import cn.hutool.core.lang.PatternPool;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.alibaba.fastjson.JSON;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.service.impl.AbstractCRUDCacheServiceImpl;
import com.mortals.xhx.base.system.message.MessageService;
import com.mortals.xhx.busiz.req.DeviceReq;
import com.mortals.xhx.busiz.rsp.ApiResp;
import com.mortals.xhx.common.code.*;
import com.mortals.xhx.common.key.Constant;
import com.mortals.xhx.common.utils.BeanUtil;
import com.mortals.xhx.module.device.dao.DeviceDao;
import com.mortals.xhx.module.device.model.DeviceEntity;
import com.mortals.xhx.module.device.model.DeviceQuery;
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.*;
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.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;

/**
 * DeviceService
 * 设备 service实现
 *
 * @author zxfei
 * @date 2022-03-09
 */
@Service("deviceService")
@Slf4j
public class DeviceServiceImpl extends AbstractCRUDCacheServiceImpl<DeviceDao, DeviceEntity, Long> implements DeviceService {

    @Autowired
    private ProductService productService;
    @Autowired
    private PlatformService platformService;
    @Autowired
    private DefaultTbCoreConsumerService consumerService;

    @Override
    protected String getExtKey(DeviceEntity data) {
        return data.getDeviceCode();
    }

    @Autowired
    private MessageService messageService;
    @Autowired
    private ICacheService cacheService;
    @Value("${thirdPartyPath:/inter/device/deviceIn}")
    private String thirdPartyPath;


    @Override
    protected void validData(DeviceEntity entity, Context context) throws AppException {
        if (ObjectUtils.isEmpty(entity.newEntity())) {
            if (ObjectUtils.isEmpty(entity.getPlatformId())) {
                throw new AppException("所属平台不能为空！");
            }
            if (ObjectUtils.isEmpty(entity.getProductId())) {
                throw new AppException("所属产品不能为空！");
            }
        }
        super.validData(entity, context);
    }

    @Override
    public ApiResp<String> sendDeviceMessage(DeviceEntity deviceEntity, TopicPartitionInfo info, TbQueueMsgHeaders header, String message, Context context) {
        ApiResp<String> resp = new ApiResp<>();
        resp.setCode(ApiRespCodeEnum.SUCCESS.getValue());
        resp.setMsg(ApiRespCodeEnum.SUCCESS.getLabel());
        TbQueueCallback callback = new TbQueueCallback() {
            @Override
            public void onSuccess(TbQueueMsgMetadata metadata) {
                log.info("消息投递成功,设备通道编码:" + deviceEntity.getDeviceMac());
            }

            @Override
            public void onFailure(Throwable t) {
                log.error("消息投递成功,设备通道编码:" + deviceEntity.getDeviceMac(), t);
            }
        };
        messageService.send(info, header, message, callback);
        return resp;
    }

    @Override
    public ApiResp<String> sendDeviceMessage(List<Long> deviceIds, TopicPartitionInfo info, TbQueueMsgHeaders header, String message, Context context) {
        ApiResp<String> resp = new ApiResp<>();
        DeviceQuery deviceQuery = new DeviceQuery();
        deviceQuery.setIdList(deviceIds);
        List<DeviceEntity> deviceEntityList = this.find(deviceQuery);
        for (DeviceEntity deviceEntity : deviceEntityList) {
            resp = sendDeviceMessage(deviceEntity, info, header, message, context);
        }
        return resp;
    }

    @Override
    public void active(String deviceCode, Context context) {
        DeviceEntity deviceEntity = this.selectOne(new DeviceQuery().deviceCode(deviceCode));
        if (ObjectUtils.isEmpty(deviceEntity)) throw new AppException("当前设备不存在！");
        if (deviceEntity.getDeviceStatus() != DeviceStatusEnum.未激活.getValue()) throw new AppException("当前设备已激活！");
        deviceEntity.setDeviceStatus(DeviceStatusEnum.离线.getValue());
        this.update(deviceEntity, context);
        PlatformEntity platformEntity = platformService.get(deviceEntity.getPlatformId());
        ProductEntity productEntity = productService.get(deviceEntity.getProductId());
        if (!ObjectUtils.isEmpty(platformEntity) && !ObjectUtils.isEmpty(productEntity)) {
            //注册rabbmit相关队列与绑定
            registerRabbitQueue(deviceEntity, platformEntity, productEntity);

            TbQueueConsumer<TbQueueMsg> mainConsumer = consumerService.getMainConsumer();
            String exchangeName = platformEntity.getPlatformSn() + Constant.EXCHANGE_SPLIT + productEntity.getProductCode();
            TopicPartitionInfo topicPartitionInfo = new TopicPartitionInfo(Constant.UPLOAD_TOPIC + deviceCode, null, exchangeName);
            Set<TopicPartitionInfo> topicPartitionInfos = new HashSet<>();
            topicPartitionInfos.add(topicPartitionInfo);
            mainConsumer.subscribe(topicPartitionInfos);
            //新增设备通知第三方平台
            sendThirdParty(deviceEntity, productEntity, platformEntity, DeviceMethodEnum.ACTIVE);
        }

    }

    @Override
    public void deviceEnabled(Long id, Integer enabled, Context context) {
        DeviceEntity deviceEntity = this.get(id, context);
        if (ObjectUtils.isEmpty(deviceEntity)) throw new AppException("当前设备不存在！");
        deviceEntity.setEnabled(enabled);
        deviceEntity.setUpdateTime(new Date());
        deviceEntity.setUpdateUserId(getContextUserId(context));
        this.update(deviceEntity, context);
        ProductEntity productEntity = productService.get(deviceEntity.getProductId());
        PlatformEntity platformEntity = platformService.get(deviceEntity.getPlatformId());

        if (enabled == YesNoEnum.YES.getValue()) {
            this.sendThirdParty(deviceEntity, productEntity, platformEntity, DeviceMethodEnum.ENABLED);
        } else {
            this.sendThirdParty(deviceEntity, productEntity, platformEntity, DeviceMethodEnum.STOP);
        }
    }


    @Override
    protected void saveAfter(DeviceEntity entity, Context context) throws AppException {
        PlatformEntity platformEntity = platformService.get(entity.getPlatformId());
        ProductEntity productEntity = productService.get(entity.getProductId());
        if (!ObjectUtils.isEmpty(platformEntity) && !ObjectUtils.isEmpty(productEntity)) {
            //注册rabbmit相关队列与绑定
            registerRabbitQueue(entity, platformEntity, productEntity);

            //新增设备通知第三方平台
            sendThirdParty(entity, productEntity, platformEntity, DeviceMethodEnum.ADD);
        } else {
            throw new AppException("产品或平台不存在！");
        }
        super.saveAfter(entity, context);
    }

    private void registerRabbitQueue(DeviceEntity entity, PlatformEntity platformEntity, ProductEntity productEntity) {
        String exchangeName = platformEntity.getPlatformSn() + Constant.EXCHANGE_SPLIT + productEntity.getProductCode();
        TopicPartitionInfo info = TopicPartitionInfo.builder().exchangeName(exchangeName).topic(Constant.UPLOAD_TOPIC + entity.getDeviceCode()).build();
        TbQueueCallback callback = new TbQueueCallback() {
            @Override
            public void onSuccess(TbQueueMsgMetadata metadata) {
                log.debug("队列创建成功,设备编码:{}", entity.getDeviceCode());
            }

            @Override
            public void onFailure(Throwable t) {
                log.error("队列创建失败,设备通道编码:{},{}", entity.getDeviceCode(), t);

            }
        };
        messageService.queueDeclare(info, callback);
        //消费监听线程添加当前声明队列
        Set<TopicPartitionInfo> partitions = new HashSet<>();
        partitions.add(info);
        consumerService.getMainConsumer().subscribe(partitions);

        //创建下行队列
        info = TopicPartitionInfo.builder().exchangeName(exchangeName).topic(Constant.DOWN_TOPIC + entity.getDeviceCode()).build();
        messageService.queueDeclare(info, callback);
    }


    @Override
    protected void updateAfter(DeviceEntity entity, Context context) throws AppException {
        PlatformEntity platformEntity = platformService.get(entity.getPlatformId());
        ProductEntity productEntity = productService.get(entity.getProductId());
        if (!ObjectUtils.isEmpty(platformEntity) && !ObjectUtils.isEmpty(productEntity)) {
            //注册rabbmit相关队列与绑定
            registerRabbitQueue(entity, platformEntity, productEntity);
            //新增设备通知第三方平台
            sendThirdParty(entity, productEntity, platformEntity, DeviceMethodEnum.UPDATE);
        }
        super.updateAfter(entity, context);
    }

    @Override
    public void sendThirdParty(DeviceEntity entity, ProductEntity productEntity, PlatformEntity platformEntity, DeviceMethodEnum update) {
        DeviceReq deviceReq = new DeviceReq();
        BeanUtils.copyProperties(entity, deviceReq, BeanUtil.getNullPropertyNames(entity));
        deviceReq.setDeviceStatus(update.getValue());
        deviceReq.setProductCode(productEntity.getProductCode());
        if (!ObjectUtils.isEmpty(platformEntity.getSendUrl())
                //&& platformEntity.getSendSwitch() == SendSwitchEnum.启用.getValue()
                && entity.getSwitchSend()) {
            //http://192.168.0.98:8090/inter/device/deviceIn
            if (PatternPool.URL_HTTP.matcher(platformEntity.getSendUrl()).find()) {
                ApiResp<String> resp = messageService.sendThirdParty(URLUtil.completeUrl(platformEntity.getSendUrl(), thirdPartyPath), deviceReq);
                log.info("sendThirtyis resp ==>{}", JSON.toJSONString(resp));
            } else {
                throw new AppException("http send url 不合法！" + platformEntity.getSendUrl());
            }
        } else {
            log.info("sendThirtyis null ==>{}", JSON.toJSONString(platformEntity));
        }
    }

    @Override
    public void putCache(String key, DeviceEntity data) {
        super.putCache(key, data);
    }


    @Override
    public DeviceDao getDeviceDao() {
        return this.getDao();
    }

    @Override
    protected void removeBefore(Long[] ids, Context context) throws AppException {
        Arrays.asList(ids).stream().forEach(id -> {
            DeviceEntity deviceEntity = this.get(id, context);
            if (!ObjectUtils.isEmpty(deviceEntity)) {
                TbQueueCallback callback = new TbQueueCallback() {
                    @Override
                    public void onSuccess(TbQueueMsgMetadata metadata) {
                        log.info("队列删除成功");
                    }

                    @Override
                    public void onFailure(Throwable t) {
                        log.error("队列删除失败", t);

                    }
                };
                messageService.delQueue(Constant.UPLOAD_TOPIC + deviceEntity.getDeviceCode(), callback);
                messageService.delQueue(Constant.DOWN_TOPIC + deviceEntity.getDeviceCode(), callback);

                PlatformEntity platformEntity = platformService.get(deviceEntity.getPlatformId());
                ProductEntity productEntity = productService.get(deviceEntity.getProductId());
                if (!ObjectUtils.isEmpty(platformEntity) && !ObjectUtils.isEmpty(productEntity)) {
                    //新增设备通知第三方平台
                    sendThirdParty(deviceEntity, productEntity, platformEntity, DeviceMethodEnum.DEL);
                }
                //删除扩展extKey
                this.removeCache(deviceEntity.getDeviceCode());
            }
        });
        super.removeBefore(ids, context);
    }

    @Override
    protected void exportAfter(DeviceEntity params, Context context, List<DeviceEntity> list) throws AppException {
        list.stream().forEach(deviceEntity -> {
            PlatformEntity platformEntity = platformService.get(deviceEntity.getPlatformId());
            ProductEntity productEntity = productService.get(deviceEntity.getProductId());
            if (!ObjectUtils.isEmpty(platformEntity) && !ObjectUtils.isEmpty(productEntity)) {
                deviceEntity.setProductCode(productEntity.getProductCode());
                deviceEntity.setPlatformCode(platformEntity.getPlatformSn());
            }
        });
        super.exportAfter(params, context, list);
    }

    @Override
    protected void saveBefore(DeviceEntity entity, Context context) throws AppException {

        if (ObjectUtils.isEmpty(entity.getDeviceCode())) {
            throw new AppException("设备编码不能为空！");
        }

        entity.setDeviceCode(StrUtil.replace(entity.getDeviceCode(), ":", "-"));
        if (ObjectUtils.isEmpty(entity.getDeviceMac())) {
            entity.setDeviceMac(entity.getDeviceCode());
        } else {
            entity.setDeviceMac(StrUtil.replace(entity.getDeviceMac(), ":", "-"));
        }

        //产品编码唯一
        DeviceEntity deviceEntity = this.selectOne(new DeviceQuery().deviceCode(entity.getDeviceCode()));
        if (!ObjectUtils.isEmpty(deviceEntity)) {
            throw new AppException("设备编码重复！");
        }


        if (!ObjectUtils.isEmpty(entity.getPlatformCode())) {
            PlatformEntity platformEntity = platformService.selectOne(new PlatformQuery().platformSn(entity.getPlatformCode()));
            if (!ObjectUtils.isEmpty(platformEntity)) {
                entity.setPlatformId(platformEntity.getId());
                entity.setPlatformName(platformEntity.getPlatformName());
            }
        }

        if (!ObjectUtils.isEmpty(entity.getProductCode())) {
            ProductEntity productEntity = productService.selectOne(new ProductQuery().productCode(entity.getProductCode()));
            if (!ObjectUtils.isEmpty(productEntity)) {
                entity.setProductId(productEntity.getId());
                entity.setProductName(productEntity.getProductName());
            }
        }
        super.saveBefore(entity, context);
    }


}