package com.yeejoin.equipmanage.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yeejoin.amos.boot.module.jcs.api.dto.IotSystemAlarmRo;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.feign.systemctl.model.MessageModel;
import com.yeejoin.equipmanage.common.entity.*;
import com.yeejoin.equipmanage.common.entity.vo.AlamVideoVO;
import com.yeejoin.equipmanage.common.enums.*;
import com.yeejoin.equipmanage.common.utils.DateUtils;
import com.yeejoin.equipmanage.common.utils.StringUtil;
import com.yeejoin.equipmanage.common.utils.UUIDUtils;
import com.yeejoin.equipmanage.common.vo.Token;
import com.yeejoin.equipmanage.fegin.JcsFeign;
import com.yeejoin.equipmanage.fegin.SystemctlFeign;
import com.yeejoin.equipmanage.mapper.*;
import com.yeejoin.equipmanage.remote.RemoteSecurityService;
import com.yeejoin.equipmanage.remote.WebMqttHandler;
import com.yeejoin.equipmanage.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;

import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class ConfirmAlarmServiceImpl extends ServiceImpl<ConfirmAlarmMapper, EquipmentSpecificAlarm> implements IConfirmAlarmService {

    private static final org.slf4j.Logger log = LoggerFactory.getLogger(ConfirmAlarmServiceImpl.class);

    private final static String FIELD_NAME = "longitude,latitude";

    @Autowired
    private RemoteSecurityService remoteSecurityService;

    static ConfirmAlarmMapper confirmAlarmMapper;
    @Autowired
    public void setConfirmAlarmMapper(ConfirmAlarmMapper confirmAlarmMapper){
        ConfirmAlarmServiceImpl.confirmAlarmMapper = confirmAlarmMapper;
    }

    private static JcsFeign jcsFeign;
    @Autowired
    public void setJcsFeign(JcsFeign jcsFeign){
        ConfirmAlarmServiceImpl.jcsFeign = jcsFeign;
    }

    @Autowired
    VideoMapper videoMapper;

    @Autowired
    IEquipmentSpecificIndexService equipmentSpecificIndexService;


    @Autowired
    MqttSendGateway mqttSendGateway;

    @Autowired
    private WebMqttHandler webMqttHandler;

    @Autowired
    private IEquipmentSpecificAlarmLogService equipmentSpecificAlarmLogService;

    private static IEquipmentSpecificSerivce equipmentSpecificSerivce;
    @Autowired
    @Lazy
    public void setIEquipmentSpecificIndexSerivce(IEquipmentSpecificSerivce equipmentSpecificSerivce){
        ConfirmAlarmServiceImpl.equipmentSpecificSerivce = equipmentSpecificSerivce;
    }

    @Autowired
    private IEquipmentSpecificIndexSerivce iEquipmentSpecificIndexSerivce;

    @Autowired
    private IVideoService videoService;

    @Value("${systemctl.jcs.switch}")
    private Boolean jcsSwitch;

    @Value("${window.vedioFormat}")
    String vedioFormat;

    @Value("${isSendApp}")
    private Boolean isSendApp;

    @Autowired
    private SystemctlFeign systemctlFeign;

    private static RuleConfirmAlarmService ruleConfirmAlamService;
    @Autowired
    public void setRuleConfirmAlamService(RuleConfirmAlarmService ruleConfirmAlamService){
        ConfirmAlarmServiceImpl.ruleConfirmAlamService = ruleConfirmAlamService;
    }

    @Autowired
    private EquipmentSpecificMapper equipmentSpecificMapper;

    @Autowired
    private EquipmentMapper equipmentMapper;

    @Autowired
    private EquipmentSpecificAlarmMapper equipmentSpecificAlarmMapper;
    
    @Autowired
    private EquipmentSpecificAlarmLogMapper equipmentSpecificAlarmLogMapper;

    @Autowired
    private ISignalClassifyService signalClassifyService;

    private static IFormInstanceService instanceService;
    @Autowired
    public void setInstanceService(IFormInstanceService instanceService){
        ConfirmAlarmServiceImpl.instanceService = instanceService;
    }

    @Autowired
    private SourceSceneMapper sourceSceneMapper;

    @Override
    public Map<String, Object> getDetailsById(Long alarmId, Long equipId, String type, String area) {
        final String videoType = "video";
        Map<String, Object> res = new HashMap<>();
        if (videoType.equals(type)) {
            List<AlamVideoVO> video = videoMapper.getVideoBySpeId(equipId);
            video.forEach(action -> {
                action.setVedioFormat(vedioFormat);
                action.setUrl(videoService.getVideoUrl(action.getName(), action.getPresetPosition(), action.getUrl(), action.getCode()));
            });
            res.put("video", video);
            return res;
        }
        EquipmentSpecificAlarmLog specificAlarm = confirmAlarmMapper.getDetailsById(alarmId, equipId);
        if (!ObjectUtils.isEmpty(specificAlarm.getConfirmType())) {
            String handleTypeName = ConfirmAlamEnum.getTypeByCode(String.valueOf(specificAlarm.getConfirmType()));
            specificAlarm.setConfirmTypeName(StringUtil.isNotEmpty(handleTypeName)
                    ? handleTypeName : signalClassifyService.getTypeNameByCode(String.valueOf(specificAlarm.getConfirmType())).getTypeName());
        }
        List<AlamVideoVO> videoBySpeId;
        if (specificAlarm == null) {
            videoBySpeId = videoMapper.getVideoBySpeId(equipId);
        } else {
            videoBySpeId = videoMapper.getVideoBySpeId(specificAlarm.getEquipmentSpecificId());
        }

        videoBySpeId.forEach(action -> {
            action.setVedioFormat(vedioFormat);
            action.setUrl(videoService.getVideoUrl(action.getName(), action.getPresetPosition(), action.getUrl(), action.getCode()));
        });
        res.put("data", specificAlarm);
        res.put("video", videoBySpeId);
        return res;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String confirmAlam(EquipmentSpecificAlarmLog ent, String appKey, String product, String token, String userId) {
        try {
            AgencyUserModel userModel = remoteSecurityService.getAgencyUser();
            ent.setConfirmUser(userModel.getUserId());
            ent.setConfirmUserName(userModel.getRealName());
            EquipmentSpecificAlarmLog alarmLog = equipmentSpecificAlarmLogService.getById(ent.getId());
            List<EquipmentSpecificAlarmLog> list = null;
            int isBatch = 0;
            if (!ObjectUtils.isEmpty(alarmLog)) {
                Long equipmentSpecificAlarmId = alarmLog.getEquipmentSpecificAlarmId();
                ent.setEquipmentSpecificAlarmId(equipmentSpecificAlarmId);
                ent.setEquipmentSpecificId(alarmLog.getEquipmentSpecificId());
                ent.setEquipmentSpecificIndexKey(alarmLog.getEquipmentSpecificIndexKey());
                Equipment equipment = equipmentSpecificMapper.getEquipmentBySpecificId(alarmLog.getEquipmentSpecificId());
                if (!StringUtil.isNotEmpty(equipment.getCleanType())) {
                    // 若此装备未定义消除策略，默认设置为复位信号自动消除
                    equipment.setCleanType(AlarmCleanTypeEnum.ZDXC.getCode());
                    equipmentMapper.updateById(equipment);
                }

                if (StringUtil.isNotEmpty(equipment.getCleanType()) && AlarmCleanTypeEnum.QRXC.getCode().equals(equipment.getCleanType())) {
                    EquipmentSpecificAlarm alarm = equipmentSpecificAlarmMapper.selectById(alarmLog.getEquipmentSpecificAlarmId());
                    alarm.setStatus(AlarmStatusEnum.HF.getCode());
                    equipmentSpecificAlarmMapper.updateById(alarm);
                    // 警情处理确认后消除更新value 为false,否则灯还在闪
                    LambdaUpdateWrapper<EquipmentSpecificIndex> updateWrapper =new LambdaUpdateWrapper<EquipmentSpecificIndex>().
                            set(EquipmentSpecificIndex::getValue,"false").
                            set(EquipmentSpecificIndex::getUpdateDate,new Date()).
                            eq(EquipmentSpecificIndex::getEquipmentSpecificId,alarm.getEquipmentSpecificId()).
                            eq(EquipmentSpecificIndex::getEquipmentIndexKey,alarm.getEquipmentSpecificIndexKey());
                    iEquipmentSpecificIndexSerivce.update(updateWrapper);
                        //指标图标显示根据 EquipmentSpecific 表中的 RealtimeIotIndexValue 判断 同步修改
                    LambdaUpdateWrapper<EquipmentSpecific> wrapper =new LambdaUpdateWrapper<EquipmentSpecific>().
                            set(EquipmentSpecific::getRealtimeIotIndexValue,"false").
                            set(EquipmentSpecific::getRealtimeIotIndexUpdateDate,new Date()).
                            eq(EquipmentSpecific::getId,alarm.getEquipmentSpecificId());
                            equipmentSpecificSerivce.update(wrapper);
                    MqttReceiveServiceImpl.upAlarmLogStatus(alarmLog.getIotCode(), alarmLog.getEquipmentSpecificIndexKey(), null, equipmentSpecificAlarmLogService, true);
                }
                //  如果是批量确警，先查询，再确警，用于批量消息推送
                isBatch = ent.getIsBatch();
                if (isBatch == 1) {
                    list = equipmentSpecificAlarmLogService.getIsConfirmByAlarmId(alarmLog.getEquipmentSpecificId(),alarmLog.getEquipmentSpecificIndexKey(), "0");
                }
            }
            if (ent.getType() != null) {
                ent.setType(ConfirmAlamEnum.getEnumByName(ent.getType()) == null ? " " : ConfirmAlamEnum.getEnumByName(ent.getType()));
            }

            ent.setUpdateDate(new Date());
            ent.setConfirmDate(new Date());
            int i = 0 ;
            ent.setConfirmTypeName(ConfirmAlamEnum.getTypeByCode(ent.getConfirmType()));
            Date date = new Date();
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String dateString = formatter.format(date);
            if (ent.isAddDefect()) {
                ent.setDefectBatchId(UUID.randomUUID().toString().replace("-", "").toLowerCase());
                ent.setResolveResult(dateString + " " + userModel.getRealName() + " 添加为缺陷进行消缺。");
            } else {
                ent.setResolveResult(dateString + " " + userModel.getRealName() + " 进行警情确认处理。");
            }
            if (ent.getIsBatch() == 0){
                i = equipmentSpecificAlarmLogMapper.updateById(ent);
            } else {
                LambdaUpdateWrapper<EquipmentSpecificAlarmLog> updateWrapper = new LambdaUpdateWrapper<EquipmentSpecificAlarmLog>().
                        eq(EquipmentSpecificAlarmLog::getEquipmentSpecificId,ent.getEquipmentSpecificId()).
                        eq(EquipmentSpecificAlarmLog::getEquipmentSpecificIndexKey,ent.getEquipmentSpecificIndexKey())
                        .isNull(EquipmentSpecificAlarmLog::getConfirmDate);
                i = equipmentSpecificAlarmLogMapper.update(ent, updateWrapper);
            }

            //int i = confirmAlarmMapper.confirmAlam(ent);

            if (i > 0) {
                if (jcsSwitch && AlarmTypeEnum.HZGJ.getCode().equals(ent.getConfirmType())) {
                    // 确警消息发送
                    if (StringUtils.isNotBlank(userId)) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    sendIotSystemAlarm(ent, userId, appKey, product, token);
                                } catch (Exception e) {
                                    log.error("sendIotSystemAlarm消息发送失败！");
                                    e.printStackTrace();
                                }
                            }
                        }).start();
                    }
                }
                if (isBatch == 1 && CollectionUtils.isNotEmpty(list)) {
                    list.stream().forEach(x ->{
                        webMqttHandler.publish(TopicEnum.EQYQR.getTopic(), JSON.parseObject(JSON.toJSONString(x), HashMap.class));
                        x.setAlarmReason(ent.getAlarmReason());
//                        syncConfirmAlarmMsgToSystemctl(x);
                    });
                } else {
//                    mqttSendGateway.sendToMqtt(TopicEnum.EQYQR.getTopic(), JSON.toJSONString(ent));
                    webMqttHandler.publish(TopicEnum.EQYQR.getTopic(), JSON.parseObject(JSON.toJSONString(ent), HashMap.class));
//                    syncConfirmAlarmMsgToSystemctl(ent);
                }
//                syncDataService.syncCreatedSendAlarmReport(ent);
            }
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    //数字换流站使用
                    mqttSendGateway.sendToMqtt(TopicEnum.EQZXDT.getTopic(), UUIDUtils.getUUID());
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("seqNo", UUID.randomUUID().toString().replace("-", "").toLowerCase());
                    mqttSendGateway.sendToMqtt(TopicEnum.ALARM_LOG_INSERT.getTopic(), jsonObject.toString());
                }
            });
            return ent.getDefectBatchId();
        } catch (Exception e) {
            e.printStackTrace();
            throw new BadRequest("确认失败");
        }
    }

    public void syncConfirmAlarmMsgToSystemctl(EquipmentSpecificAlarmLog equipmentSpecificAlarmLog) {
        try {
            MessageModel model = new MessageModel();
            String alarmReason = ValidationUtil.isEmpty(equipmentSpecificAlarmLog.getAlarmReason()) ? "" : equipmentSpecificAlarmLog.getAlarmReason();
            if (alarmReason.contains("：")) {
                String[] split = alarmReason.split("：");
                alarmReason = split[1];
            }
            model.setTitle(equipmentSpecificAlarmLog.getEquipmentSpecificIndexName());
            String body = String.format("警情类型：%s；报警设备：%s；报警位置：%s；报警原因：%s；报警时间：%s",
                    equipmentSpecificAlarmLog.getEquipmentSpecificIndexName(), equipmentSpecificAlarmLog.getEquipmentSpecificName(),
                    equipmentSpecificAlarmLog.getLocation(), alarmReason,
                    DateUtils.date2LongStr(equipmentSpecificAlarmLog.getCreateDate()));
            model.setBody(body);
            model.setMsgType("iotMonitor");
            if (isSendApp){
                model.setIsSendApp(true);
                model.setTerminal("APP/WEB");
            } else {
                model.setIsSendApp(false);
                model.setTerminal("WEB");
            }
            model.setIsSendWeb(true);
            model.setCategory(1);
            model.setRelationId(String.valueOf(equipmentSpecificAlarmLog.getId()));
            Token token = remoteSecurityService.getServerToken();
            systemctlFeign.create(token.getAppKey(), token.getProduct(), token.getToke(), model);
            log.debug(String.format("调用平台消息服务成功：%s", JSON.toJSONString(model)));
        } catch (Exception e) {
            log.error("告警消息同步平台失败：syncSystemctlMsg，===>>>" + e.getMessage());
        }
    }

    @Override
    public Integer getFireAlarm() {
        return confirmAlarmMapper.getFireAlarm();
    }

    @Override
    public Integer getFaultAlarm() {
        return confirmAlarmMapper.getFaultAlarm();
    }

    @Override
    public Map<String, Object> getEquipSceneAndRelationVideo(Long equipmentSpecificId) {
        Map<String, Object> res = new HashMap<>();
        // 设备关联的摄像头
        List<AlamVideoVO> video = videoMapper.getVideoBySpeId(equipmentSpecificId);
        video.forEach(action -> {
            action.setVedioFormat(vedioFormat);
            action.setUrl(videoService.getVideoUrl(action.getName(), action.getPresetPosition(), action.getUrl(), action.getCode()));
        });
        res.put("video", video);
        // 设备所在楼层画布
        SourceScene scene = sourceSceneMapper.queryEquipmentScene(equipmentSpecificId);
        res.put("scene", scene);
        return res;
    }

//    public void sendIotSystemAlarm(EquipmentSpecificAlarmLog ent, String userId, String appKey, String product, String token){
////        Token serverToken = remoteSecurityService.getServerToken();
//        ResponseModel<List<UserDto>> responseModel = null;
//        try {
//            responseModel = jcsFeign.getUserInfo(appKey, product, token, userId);
//        } catch (Exception e) {
//            log.error("查询机场人员为空，检查机场人员是否绑定单位！");
//        }
//        List<UserDto> result = responseModel.getResult();
//        IotSystemAlarmRo confirmAlamVo = new IotSystemAlarmRo();
//        confirmAlamVo.setId(ent.getId());
//        if (CollectionUtils.isNotEmpty(result)) {
//            result.stream().forEach(x -> {
//                confirmAlamVo.setUnitInvolvedId(x.getCompanyId());
//                confirmAlamVo.setUnitInvolvedName(x.getCompanyName());
//                String bizOrgType = x.getBizOrgType();
//                String fieldCode = x.getFieldCode();
//                String fieldValue = x.getFieldValue();
//                String personName = x.getPersonName();
//                if ("PERSON".equalsIgnoreCase(bizOrgType)) {
//                    confirmAlamVo.setContactUser(personName);
//                    confirmAlamVo.setContactPhone(fieldValue);
//                } else if ("COMPANY".equalsIgnoreCase(bizOrgType)) {
//                    switch (fieldCode) {
//                        case "companyLocation":
//                            confirmAlamVo.setAddress(fieldValue);
//                            break;
//                        case "longitude":
//                            confirmAlamVo.setLongitude(getVal(fieldValue));
//                            break;
//                        case "latitude":
//                            confirmAlamVo.setLatitude(getVal(fieldValue));
//                            break;
//                        default:
//                    }
//                }
//                List<UserDto> infoList = equipmentSpecificSerivce.getEquipSpecificLocationInfo(ent.getEquipmentSpecificId(), FIELD_NAME.split(","));
//                if (CollectionUtils.isNotEmpty(infoList)) {
//                    infoList.stream().forEach(dto -> {
//                        String name = dto.getPersonName();
//                        String code = dto.getFieldCode();
//                        String value = dto.getFieldValue();
//                        confirmAlamVo.setFireLocation(name);
//                        switch (code) {
//                            case "longitude":
//                                confirmAlamVo.setFloorLongitude(getVal(value));
//                                break;
//                            case "latitude":
//                                confirmAlamVo.setFloorLatitude(getVal(value));
//                                break;
//                            default:
//                        }
//                    });
//                }
//            });
//        }
//        try {
//            ruleConfirmAlamService.confirmAlam(confirmAlamVo, appKey, product, token);
//        } catch (Exception e) {
//            log.error("发送接处警消息失败！");
//        }
//    }


    //查询当前建筑是否是 最顶级建筑
    public static List<FormInstance> selectBuildingById(List<FormInstance> formInstances){
        if (formInstances.get(0).getGroupType().equals("building")){
            return formInstances;
        }
        String parentId = null;
        for (FormInstance formInstance : formInstances) {
            if (formInstance.getFieldName().equals("parentId")){
               parentId =formInstance.getFieldValue();
            }
        }
        LambdaQueryWrapper<FormInstance> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FormInstance::getInstanceId,parentId);
        formInstances = instanceService.getBaseMapper().selectList(wrapper);
        return  selectBuildingById(formInstances);
    }


    public static void sendIotSystemAlarm(EquipmentSpecificAlarmLog ent, String userId, String appKey, String product, String token){
//        Token serverToken = remoteSecurityService.getServerToken();
        IotSystemAlarmRo confirmAlamVo = new IotSystemAlarmRo();
        confirmAlamVo.setId(ent.getId());
        ent = confirmAlarmMapper.getDetailsById(ent.getId(), null);
        EquipmentSpecific equipmentSpecific = equipmentSpecificSerivce.getById(ent.getEquipmentSpecificId());

        List<FormInstance> formInstances =  new ArrayList<>();
        //现在需要返回设备的所在建筑及经纬度 查询当前设备所在建筑
        if(!ValidationUtil.isEmpty(equipmentSpecific.getWarehouseStructureId())){
            LambdaQueryWrapper<FormInstance> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(FormInstance::getInstanceId,equipmentSpecific.getWarehouseStructureId());
            formInstances = instanceService.getBaseMapper().selectList(wrapper);
        }
        //判断所在建筑是否是顶级建筑 房间及楼层是没有经纬度的 向上查询
        if (!ValidationUtil.isEmpty(formInstances)){
            formInstances = selectBuildingById(formInstances);
        }
        String address = null ;
        String latitude= null ;
        String longitude= null ;

        if (!ValidationUtil.isEmpty(formInstances)){
            for (FormInstance formInstance : formInstances) {
                if (formInstance.getFieldName().equals("address")){
                    address =formInstance.getFieldValue();
                    if (address.contains("@")){
                        String[] split = address.split("@");
                        address = split[0];
                    }
                }
                if (formInstance.getFieldName().equals("latitude")){
                    latitude =formInstance.getFieldValue();
                }
                if (formInstance.getFieldName().equals("longitude")){
                    longitude =formInstance.getFieldValue();
                }
            }
        }


        if (!ValidationUtil.isEmpty(equipmentSpecific.getAgencyId())){
            // 机场单位
            JSONObject unitMap = jcsFeign.getUnitById(appKey, product, token, equipmentSpecific.getAgencyId()).getResult();
            JSONObject jsonObject = unitMap.getJSONObject("map");
            confirmAlamVo.setUnitInvolvedId(equipmentSpecific.getAgencyId());
            confirmAlamVo.setUnitInvolvedName(unitMap.getString("bizOrgName"));
            confirmAlamVo.setAddress(address == null ? jsonObject.getString("companyLocation"):address);
            confirmAlamVo.setLongitude(longitude== null?jsonObject.getDouble("longitude"): Double.valueOf(longitude));
            confirmAlamVo.setLatitude(latitude == null?jsonObject.getDouble("latitude"):Double.valueOf(latitude));
        }
        try {
            // 机场人员
            JSONObject personMap = jcsFeign.getPersonByUserId(appKey, product, token, userId).getResult();
            confirmAlamVo.setContactUser(personMap.getString("bizOrgName"));
            confirmAlamVo.setContactPhone(personMap.getJSONObject("map").getString("telephone"));
        } catch (Exception e) {
            log.error("查询机场人员为空，检查机场人员是否绑定单位！");
        }
        confirmAlamVo.setFireLocation(ent.getLocation());
        Map<String, Double> equipLocationInfo = equipmentSpecificSerivce.getEquipLocationInfo(ent.getEquipmentSpecificId());

        if (!ObjectUtils.isEmpty(equipLocationInfo)) {
            if (equipLocationInfo.containsKey("longitude")){
                confirmAlamVo.setFloorLongitude(equipLocationInfo.get("longitude"));
            }
            if (equipLocationInfo.containsKey("latitude")){
                confirmAlamVo.setFloorLatitude(equipLocationInfo.get("latitude"));
            }
        }
        try {
            ruleConfirmAlamService.confirmAlam(confirmAlamVo, appKey, product, token);
        } catch (Exception e) {
            log.error("发送接处警消息失败！");
        }
    }

    private Double getVal(String value){
        return ValidationUtil.isEmpty(value) ? null : Double.parseDouble(value);
    }
}
