package com.zd.airbottle.service.impl;

import com.zd.airbottle.domain.AlarmRecord;
import com.zd.airbottle.domain.QpUseRecord;
import com.zd.airbottle.domain.vo.AlarmRecordVo;
import com.zd.airbottle.domain.vo.BottleStorageInfoVo;
import com.zd.airbottle.domain.vo.QpBottleStorageRVo;
import com.zd.airbottle.mapper.AlarmRecordMapper;
import com.zd.airbottle.service.IAlarmRecordService;
import com.zd.airbottle.service.IQpBottleStorageService;
import com.zd.airbottle.service.IQpUseRecordService;
import com.zd.common.core.constant.HttpStatus;
import com.zd.common.core.domain.R;
import com.zd.common.core.template.TemplateResult;
import com.zd.common.core.utils.StringUtils;
import com.zd.common.core.web.domain.AjaxResult;
import com.zd.common.redis.service.RedisService;
import com.zd.system.api.RemoteUserService;
import com.zd.system.api.alarm.RemoteAlarmService;
import com.zd.system.api.alarm.domain.AlarmEntrty;
import com.zd.system.api.alarm.domain.Routes;
import com.zd.system.api.alarm.domain.SendTypes;
import com.zd.system.api.domain.InventoryTag;
import com.zd.system.api.laboratory.RemoteLaboratoryService;
import com.zd.system.api.laboratory.RemoteSubQueryService;
import com.zd.system.api.laboratory.domain.LabSubject;
import com.zd.system.api.laboratory.domain.RemoteLabHardware;
import com.zd.system.api.message.RemoteMessageService;
import com.zd.system.api.netty.RemoteNettyService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 报警记录Service业务层处理
 */
@Service
@Slf4j
public class AlarmRecordServiceImpl implements IAlarmRecordService {
    @Resource
    private AlarmRecordMapper alarmRecordMapper;
    @Resource
    private IQpBottleStorageService storageService;
    @Resource
    private IQpUseRecordService useRecordService;
    @Resource
    private RedisService redisService;
    @Resource
    private RemoteAlarmService remoteAlarmService;
    @Resource
    private RemoteSubQueryService remoteSubQueryService;
    @Resource
    private RemoteLaboratoryService laboratoryService;
    @Resource
    private RemoteUserService userService;
    @Resource
    private RemoteMessageService messageService;
    @Resource
    private RemoteNettyService remoteNettyService;

    private static final String FRID_CODE = "FRID:";

    /**
     * 查询报警记录列表
     *
     * @param alarmRecord 报警记录
     * @return 报警记录
     */
    @Override
    public List<AlarmRecord> selectAlarmRecordList(AlarmRecord alarmRecord) {
        return alarmRecordMapper.selectAlarmRecordList(alarmRecord);
    }

    @Override
    public List<AlarmRecord> getListByIds(List<Long> ids) {
        if (ids.isEmpty()) {
            new ArrayList<>();
        }
        return alarmRecordMapper.getListByIds(ids);
    }

    /**
     * 新增报警记录
     * 默认新增气瓶报警记录
     *
     * @param alarmRecord 报警记录
     * @param hardware RFID 设备数据
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertAlarmRecord(AlarmRecord alarmRecord, RemoteLabHardware hardware) {
        String electronicTag = alarmRecord.getElectronicTag();
        QpBottleStorageRVo storageRVo = storageService.getByElectronicTag(electronicTag);
        if (storageRVo != null) {
            if (hardware!=null){
                //RFID设备报警
                R<Boolean> alarm = remoteNettyService.alarm(hardware);
                log.info("==================>{},{}",alarm.getCode(),alarm.getMsg());
            }
            Long id = storageRVo.getId();
            String key = FRID_CODE + electronicTag + id;
            String frid = redisService.getCacheObject(key);
            if (frid != null) {
                return 1;
            }
            // 发送报警消息
            sendAlarm(storageRVo);
            redisService.setCacheObject(key, electronicTag, 300L, TimeUnit.SECONDS);
            alarmRecord.setAlarmTime(Calendar.getInstance().getTime())
                    .setMasterId(id)
                    .setType(1)
                    .setProductType(1);
            return alarmRecordMapper.insertAlarmRecord(alarmRecord);
        }else {
            if (hardware!=null){
                log.info("==================>{},{}",alarmRecord.getElectronicTag(),"标签无数据");
            }
        }
        return 0;
    }

    private void sendAlarm(QpBottleStorageRVo storageRVo) {
        Long subjectId = storageRVo.getSubjectId();
        R<List<LabSubject>> resultList = remoteSubQueryService.listByIds(Collections.singletonList(subjectId));
        if (resultList.getCode() == HttpStatus.SUCCESS) {
            List<LabSubject> data = resultList.getData();
            if (data != null && !data.isEmpty()) {
                LabSubject labSubject = data.get(0);
                String subjectName = labSubject.getName();
                //实验室负责人账号ID
                Long adminId = labSubject.getAdminId();
                //安全责任人ID
                String safeUserId = labSubject.getSafeUserId();
                //触发声光报警
                sendHardware(labSubject, subjectName);
                //发送微信模板消息
                sendWxMessage(storageRVo, labSubject);
                //发送电话警报
                sendPhone(storageRVo, subjectName, adminId, safeUserId);
            }
        }
    }

    private void sendHardware(LabSubject labSubject, String subjectName) {
        RemoteLabHardware remoteLabHardware = new RemoteLabHardware();
        remoteLabHardware.setType(8);
        Long id = labSubject.getId();
        remoteLabHardware.setSubjectId(id);
        R<List<RemoteLabHardware>> hardwareResult = laboratoryService.remoteList(remoteLabHardware);
        if (hardwareResult.getCode() == HttpStatus.SUCCESS) {
            List<RemoteLabHardware> hardwareList = hardwareResult.getData();
            if (!hardwareList.isEmpty()) {
                RemoteLabHardware hardware = hardwareList.get(0);
                laboratoryService.controlByInside(hardware.getId(), "01");
                // 控制响铃时长
                if (hardware.getRingTime() != null) {
                    ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder().namingPattern("alarm-pool-%d").daemon(true).build());
                    executorService.schedule(() -> laboratoryService.controlByInside(hardware.getId(), "00"), hardware.getRingTime(), TimeUnit.SECONDS);
                }
            } else {
                log.error("实验室【" + subjectName + "】ID" + id + "未设置或启用声光报警器！");
            }
        }
    }

    private void sendPhone(QpBottleStorageRVo storageRVo, String subjectName, Long adminId, String safeUserId) {
        List<String> phones = new ArrayList<>();
        R<List<String>> listR = userService.getPhoneByUserIDS(adminId + "," + safeUserId);
        if (listR.getCode() == HttpStatus.SUCCESS && !listR.getData().isEmpty()) {
            phones.addAll(listR.getData());
        }
        String ownerPhone = storageRVo.getOwnerPhone();
        if (ownerPhone != null) {
            phones.add(ownerPhone);
        }
        String airName = storageRVo.getAirName();
        //电话报警
        AlarmEntrty alarmEntrty = new AlarmEntrty();
        alarmEntrty.setRoute(Routes.NoticePush);
        alarmEntrty.setType(SendTypes.Call + "");
        alarmEntrty.setTo(phones.toArray(new String[]{}));
        alarmEntrty.setText(subjectName + airName + "气瓶被违规带离，请尽快确认");
        AjaxResult result = remoteAlarmService.send(alarmEntrty);
        if (!result.get(AjaxResult.CODE_TAG).equals(HttpStatus.SUCCESS)){
            log.error("电话报警异常：发送实验室【{}】,实验室ID【{}】,接收用户手机号【{}】",subjectName,storageRVo.getSubjectId(), phones);
        }
    }

    private void sendWxMessage(QpBottleStorageRVo storageRVo, LabSubject labSubject) {
        //实验室负责人账号ID
        Long adminId = labSubject.getAdminId();
        //安全责任人ID
        String safeUserId = labSubject.getSafeUserId();
        Long ownerId = storageRVo.getOwnerId();
        ArrayList<Long> userIds = new ArrayList<>();
        userIds.add(ownerId);
        userIds.add(adminId);
        if (safeUserId != null) {
            String[] split = safeUserId.split(",");
            for (String str : split) {
                userIds.add(Long.valueOf(str));
            }
        }
        R<TemplateResult> result = messageService.sendAlarm(userIds, labSubject.getName());
        if (result.getCode()!=HttpStatus.SUCCESS){
            log.error("微信模板消息发送异常：发送实验室【{}】,实验室ID【{}】,接收用户ID【{}】",labSubject.getName(),labSubject.getId(),userIds);
        }
    }

    @Override
    public void getRecordInfo(List<AlarmRecordVo> recordVos) {
        List<Long> masterIds = recordVos.stream().filter(alarmRecordVo -> alarmRecordVo.getProductType() == 1).map(AlarmRecordVo::getMasterId).collect(Collectors.toList());
        List<QpBottleStorageRVo> storageRVos = storageService.getByIds(masterIds);
        List<QpUseRecord> useRecords = useRecordService.getInUseByStorageIds(masterIds);
        Map<Long, QpBottleStorageRVo> storageRVoMap = storageRVos.stream().collect(Collectors.toMap(QpBottleStorageRVo::getId, s -> s));
        Map<Long, QpUseRecord> recordMap = useRecords.stream().collect(Collectors.toMap(QpUseRecord::getStorageId, s -> s));
        recordVos.forEach(r -> {
            Long masterId = r.getMasterId();
            if (storageRVoMap.containsKey(masterId)) {
                QpBottleStorageRVo storageRVo = storageRVoMap.get(masterId);
                r.setCurrentPressure(storageRVo.getCurrentPressure())
                        .setAirName(storageRVo.getAirName())
                        .setConfigName(storageRVo.getConfigName())
                        .setLocation(storageRVo.getLocation())
                        .setOwner(storageRVo.getOwner())
                        .setOwnerId(storageRVo.getOwnerId())
                        .setOwnerPhone(storageRVo.getOwnerPhone());
            }
            if (recordMap.containsKey(masterId)) {
                QpUseRecord useRecord = recordMap.get(masterId);
                r.setCurrentUser(useRecord.getContacts()).setCurrentPhone(useRecord.getPhone());
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean remoteAdd(InventoryTag tag) {
        return insertAlarmRecord(new AlarmRecord().setElectronicTag(tag.getEpc()),tag.getRemoteLabHardware())==1;
    }

    @Override
    public List<BottleStorageInfoVo> setMasterIds(AlarmRecord alarmRecord) {
        if (!StringUtils.isEmpty(alarmRecord.getSearchValue())) {
            BottleStorageInfoVo storageInfoVo = new BottleStorageInfoVo();
            storageInfoVo.setSearchValue(alarmRecord.getSearchValue());
            return storageService.getStorageInfoList(storageInfoVo);
        }
        return Collections.emptyList();
    }
}
