package com.yeejoin.equipmanage.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.component.emq.EmqKeeper;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.equipmanage.common.datasync.entity.FireEquipment;
import com.yeejoin.equipmanage.common.datasync.entity.FireEquipmentDefectAlarm;
import com.yeejoin.equipmanage.common.datasync.entity.FireEquipmentFaultAlarm;
import com.yeejoin.equipmanage.common.datasync.entity.FireEquipmentFireAlarm;
import com.yeejoin.equipmanage.common.datasync.entity.FireFightingSystem;
import com.yeejoin.equipmanage.common.datasync.entity.FireVehicle;
import com.yeejoin.equipmanage.common.datasync.entity.publics.SyncDataMessage;
import com.yeejoin.equipmanage.common.datasync.enums.SyncDataOperationEnum;
import com.yeejoin.equipmanage.common.datasync.enums.SyncDataTypeEnum;
import com.yeejoin.equipmanage.common.datasync.vo.AppAlarmExtVo;
import com.yeejoin.equipmanage.common.datasync.vo.AppAlarmRportVo;
import com.yeejoin.equipmanage.common.datasync.vo.AppAlarmVo;
import com.yeejoin.equipmanage.common.datasync.vo.RequestVo;
import com.yeejoin.equipmanage.common.entity.Car;
import com.yeejoin.equipmanage.common.entity.EquipmentSpecificAlarmLog;
import com.yeejoin.equipmanage.common.entity.FormInstance;
import com.yeejoin.equipmanage.common.entity.vo.CarPropertyVo;
import com.yeejoin.equipmanage.common.entity.vo.EquipmentIndexVO;
import com.yeejoin.equipmanage.common.entity.vo.EquipmentSpecificVo;
import com.yeejoin.equipmanage.common.utils.HttpContentTypeUtil;
import com.yeejoin.equipmanage.mapper.EquipmentSpecificAlarmLogMapper;
import com.yeejoin.equipmanage.mapper.EquipmentSpecificMapper;
import com.yeejoin.equipmanage.service.ISyncDataService;
import com.yeejoin.equipmanage.utils.DcsUtil;
import com.yeejoin.equipmanage.utils.SyncDataUtil;

/**
 * <h1>数据同步服务</h1>
 *
 * @Author Jianqiang Gao
 * @Date 2021-04-01 14:28
 */
@Service("syncDataService")
@Async("equipAsyncExecutor")
public class SyncDataServiceImpl implements ISyncDataService {

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

    @Value("${dcs.client-id}")
    private String clientId;

    @Value("${dcs.url.sendalarm}")
    private String sendAlarmUrl;

    @Value("${dcs.x.hw.id}")
    private String xHwId;

    @Value("${dcs.x.hw.appKey}")
    private String xHwAppKey;

    @Autowired
    private DcsUtil dcsUtil;

    @Autowired
    private EmqKeeper emqKeeper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private EquipmentSpecificMapper equipmentSpecificMapper;

    @Autowired
    private EquipmentSpecificAlarmLogMapper equipmentSpecificAlarmLogMapper;


    /**
     * 同步创建巡检项
     *
     * @param fireEquipment 新建对象
     */
    @Override
    public void syncCreatedEquipmentSpecific(FireEquipment fireEquipment) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(fireEquipment, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncCreatedEquipmentSpecific(Collection<FireEquipment> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    /**
     * 同步删除巡检项
     *
     * @param ids 删除的id列表
     */
    @Override
    public void syncDeletedEquipmentSpecific(Collection<Long> ids) {
        List<FireEquipment> list = ids.stream().map(id -> {
            FireEquipment fireEquipment = new FireEquipment();
            fireEquipment.setId(String.valueOf(id));
            return fireEquipment;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.DELETE);
        sendMessage(message);
    }

    /**
     * 同步更新巡检项
     *
     * @param list 更新列表
     */
    @Override
    public void syncUpdatedEquipmentSpecific(Collection<FireEquipment> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    /**
     * 同步创建巡检点
     *
     * @param formInstance 新建对象
     */
    @Override
    public void syncCreatedFormInstance(FormInstance formInstance) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(formInstance, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncCreatedFormInstance(Collection<FormInstance> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    /**
     * 同步删除巡检点
     *
     * @param ids 删除的id列表
     */
    @Override
    public void syncDeletedFormInstance(Collection<Long> ids) {
        List<FormInstance> list = ids.stream().map(id -> {
            FormInstance formInstance = new FormInstance();
            formInstance.setId(id);
            return formInstance;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    /**
     * 同步更新巡检点
     *
     * @param list 更新列表
     */
    @Override
    public void syncUpdatedFormInstance(Collection<FormInstance> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncCreatedBuilding(List<FormInstance> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_BUILDING.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedFloor(List<FormInstance> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FLOOR.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedRoom(List<FormInstance> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_ROOM.getSign());
        sendMessage(message);
    }

    @Override
    public void syncDeletedBuilding(Collection<Long> ids) {
        List<FormInstance> list = ids.stream().map(id -> {
            FormInstance formInstance = new FormInstance();
            formInstance.setInstanceId(id);
            return formInstance;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.DELETE, SyncDataTypeEnum.AST_BUILDING.getSign());
        sendMessage(message);
    }

    @Override
    public void syncDeletedFloor(Collection<Long> ids) {
        List<FormInstance> list = ids.stream().map(id -> {
            FormInstance formInstance = new FormInstance();
            formInstance.setInstanceId(id);
            return formInstance;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.DELETE, SyncDataTypeEnum.AST_FLOOR.getSign());
        sendMessage(message);
    }

    @Override
    public void syncDeletedRoom(Collection<Long> ids) {
        List<FormInstance> list = ids.stream().map(id -> {
            FormInstance formInstance = new FormInstance();
            formInstance.setInstanceId(id);
            return formInstance;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.DELETE, SyncDataTypeEnum.AST_ROOM.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedEquipmentSpecificInfo(EquipmentIndexVO fireEquipmentInfo) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(fireEquipmentInfo, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_EQUIP_INFO.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedEquipmentSpecificInfo(Collection<EquipmentIndexVO> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_EQUIP_INFO.getSign());
        sendMessage(message);
    }

    @Override
    public void syncDeletedEquipmentSpecificInfo(Collection<Long> ids) {
        List<EquipmentIndexVO> list = ids.stream().map(id -> {
            EquipmentIndexVO equipmentIndexVO = new EquipmentIndexVO();
            equipmentIndexVO.setId(id);
            return equipmentIndexVO;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.DELETE, SyncDataTypeEnum.AST_FIRE_EQUIP_INFO.getSign());
        sendMessage(message);
    }

    @Override
    public void syncUpdatedEquipmentSpecificInfo(Collection<EquipmentIndexVO> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_EQUIP_INFO.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireEquipMeasurement(EquipmentIndexVO fireEquipMeasurement) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(fireEquipMeasurement, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_EQUIP_MEASUREMENT.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireEquipMeasurement(Collection<EquipmentIndexVO> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_EQUIP_MEASUREMENT.getSign());
        sendMessage(message);
    }

    @Override
    public void syncDeletedFireEquipMeasurement(Collection<Long> ids) {
        List<EquipmentIndexVO> list = ids.stream().map(id -> {
            EquipmentIndexVO equipmentIndexVO = new EquipmentIndexVO();
            equipmentIndexVO.setId(id);
            return equipmentIndexVO;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.DELETE, SyncDataTypeEnum.AST_FIRE_EQUIP_MEASUREMENT.getSign());
        sendMessage(message);
    }

    @Override
    public void syncUpdatedFireEquipMeasurement(Collection<EquipmentIndexVO> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_EQUIP_MEASUREMENT.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireVehicle(FireVehicle car) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(car, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireVehicle(Collection<FireVehicle> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncDeletedFireVehicle(Collection<Long> ids) {
        List<FireVehicle> list = ids.stream().map(id -> {
            FireVehicle fireVehicle = new FireVehicle();
            fireVehicle.setId(String.valueOf(id));
            return fireVehicle;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.DELETE);
        sendMessage(message);
    }

    @Override
    public void syncUpdatedFireVehicle(Collection<Car> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireVehicleInfo(CarPropertyVo carProperty) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(carProperty, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_VEHICLE_INFO.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireVehicleInfo(Collection<CarPropertyVo> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_VEHICLE_INFO.getSign());
        sendMessage(message);
    }

    @Override
    public void syncDeletedFireVehicleInfo(Collection<Long> ids) {
        List<CarPropertyVo> list = ids.stream().map(id -> {
            CarPropertyVo carPropertyVo = new CarPropertyVo();
            carPropertyVo.setId(id);
            return carPropertyVo;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.DELETE, SyncDataTypeEnum.AST_FIRE_VEHICLE_INFO.getSign());
        sendMessage(message);
    }

    @Override
    public void syncUpdatedFireVehicleInfo(Collection<CarPropertyVo> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_VEHICLE_INFO.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireVehicleMeasurement(CarPropertyVo carPropertyVo) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(carPropertyVo, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_VEHICLE_MEASUREMENT.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireVehicleMeasurement(Collection<CarPropertyVo> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_VEHICLE_MEASUREMENT.getSign());
        sendMessage(message);
    }

    @Override
    public void syncDeletedFireVehicleMeasurement(Collection<Long> ids) {
        List<CarPropertyVo> list = ids.stream().map(id -> {
            CarPropertyVo carPropertyVo = new CarPropertyVo();
            carPropertyVo.setId(id);
            return carPropertyVo;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.DELETE, SyncDataTypeEnum.AST_FIRE_VEHICLE_MEASUREMENT.getSign());
        sendMessage(message);
    }

    @Override
    public void syncUpdatedFireVehicleMeasurement(Collection<CarPropertyVo> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE, SyncDataTypeEnum.AST_FIRE_VEHICLE_MEASUREMENT.getSign());
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireFightingSystem(FireFightingSystem fireFightingSystem) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(fireFightingSystem, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireFightingSystem(Collection<FireFightingSystem> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncDeletedFireFightingSystem(Collection<Long> ids) {
        List<FireFightingSystem> list = ids.stream().map(id -> {
            FireFightingSystem fireFightingSystem = new FireFightingSystem();
            fireFightingSystem.setId(String.valueOf(id));
            return fireFightingSystem;
        }).collect(Collectors.toList());
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.DELETE);
        sendMessage(message);
    }

    @Override
    public void syncUpdatedFireFightingSystem(Collection<FireFightingSystem> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncCreatedSendAlarm(Collection<EquipmentSpecificAlarmLog> list) {
        equipAlarmDataSync((List<EquipmentSpecificAlarmLog>) list);
    }

    @Override
    public void syncCreatedFireEquipAlarm(Collection<FireEquipmentFireAlarm> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireEquiptFaultAlarm(Collection<FireEquipmentFaultAlarm> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncCreatedFireEquipDefectAlarm(Collection<FireEquipmentDefectAlarm> list) {
        SyncDataMessage message = SyncDataUtil.buildSyncMessage(list, SyncDataOperationEnum.CREATE);
        sendMessage(message);
    }

    @Override
    public void syncCreatedSendAlarmReport(EquipmentSpecificAlarmLog ent) {
        equipAlarmDataSync(Arrays.asList(ent));
    }

    private AppAlarmRportVo getAppAlarmRportVo(AppAlarmExtVo vo) {
        AppAlarmRportVo alarmRportVo = new AppAlarmRportVo();
        alarmRportVo.setTime(vo.getConfirmtime());
        alarmRportVo.setEventdesc(vo.getEventdesc());
        alarmRportVo.setEventreason(vo.getEventreason());
        return alarmRportVo;
    }

    private void sendMessage(SyncDataMessage message) {
        try {
            emqKeeper.getMqttClient().publish(message.getType().getMqTopic(), message.message2Bytes(), 2, false);
        } catch (MqttException e) {
            e.printStackTrace();
        }
        //暂时屏蔽同步时存储redis
        //redisTemplate.opsForValue().set(message.redisKey(), new String(message.message2Bytes()));
    }

    void equipAlarmDataSync(List<EquipmentSpecificAlarmLog> list) {
        if (CollectionUtils.isNotEmpty(list)) {
            List<Long> idList = list.stream().filter(x -> x.getBuildId() != null).map(EquipmentSpecificAlarmLog::getId).collect(Collectors.toList());
            List<Long> idBNullList = list.stream().filter(x -> x.getBuildId() == null).map(EquipmentSpecificAlarmLog::getId).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(idList) || CollectionUtils.isNotEmpty(idBNullList)) {
                List<AppAlarmExtVo> appAlarmVoList = new ArrayList<>();
                List<AppAlarmExtVo> appAlarmVoList1 = new ArrayList<>();
                if (CollectionUtils.isNotEmpty(idList)) {
                    appAlarmVoList = equipmentSpecificAlarmLogMapper.findByIdList(idList);
                }
                if (CollectionUtils.isNotEmpty(idBNullList)) {
                    appAlarmVoList1 = equipmentSpecificAlarmLogMapper.findByIdListNoBuildId(idBNullList);
                }
                appAlarmVoList.addAll(appAlarmVoList1);
                if (CollectionUtils.isNotEmpty(appAlarmVoList)) {
                    List<AppAlarmExtVo> collect = appAlarmVoList.stream().filter(x -> x.getDeviceid() != null).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(collect)) {
                        try {
                            String authorization = dcsUtil.getDcsToken();
                            Map<String, String> headerMap = new HashMap<>();
                            headerMap.put("Authorization", authorization);
                            headerMap.put("token", authorization.split(" ")[1]);
                            headerMap.put("X-HW-ID", xHwId);
                            headerMap.put("X-HW-APPKEY", xHwAppKey);
                            if (StringUtils.isNotBlank(authorization)) {
                                RequestVo requestVo = new RequestVo();
                                requestVo.setId(10011L);
                                requestVo.setClientId(clientId);
                                Map<String, Object> warnMap = new HashMap<>();
                                List<Object> alarmList = new ArrayList<>();
                                for (AppAlarmExtVo alarmVo : collect) {
                                    Boolean isreport = alarmVo.getIsreport();
                                    Map<String, Object> map = new LinkedHashMap<>();
                                    AppAlarmVo appAlarmVo = new AppAlarmVo();
                                    BeanUtils.copyProperties(alarmVo, appAlarmVo);
                                    map.put("alarm", appAlarmVo);
                                    if (isreport) {
                                        map.put("report", getAppAlarmRportVo(alarmVo));
                                    } else {
                                        map.put("report", new AppAlarmRportVo());
                                    }
                                    alarmList.add(map);
                                }
                                warnMap.put("warns", alarmList);
                                requestVo.setBody(warnMap);
                                String s = HttpContentTypeUtil.sendHttpPostJsonWithHeader(sendAlarmUrl, JSON.toJSONString(requestVo), headerMap);
                                logger.info("===============告警推送联调==================返回数据：" + s);
                            }
                        } catch (Exception e) {
                            logger.error("equipAlarmDataSync告警数据发送接口请求异常：" + e.getMessage());
                        }
                    }
                }
            }
        }
    }

    @Async("equipAsyncExecutor")
    @Override
    public void saveOrUpdateEquipIotCodeRedisData(List<EquipmentSpecificVo> data) {
        // TODO Auto-generated method stub
        List<EquipmentSpecificVo> equipAndCars = new ArrayList<EquipmentSpecificVo>();
        System.out.println("===============saveOrUpdateEquipIotCodeRedisData====================");
        if (!ObjectUtils.isEmpty(data)) {
            equipAndCars = data;
        } else {
            equipAndCars = equipmentSpecificMapper.getEquipOrCarByIotCode(null);
        }
        redisUtils.set("equipAndCarIotCodes", JSONObject.toJSONString(equipAndCars));
    }

}
