package com.zd.bottle.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zd.bottle.domain.AlarmRecord;
import com.zd.bottle.domain.BottleStorage;
import com.zd.bottle.domain.RfidTag;
import com.zd.bottle.domain.UsegasApply;
import com.zd.bottle.mapper.AlarmRecordMapper;
import com.zd.bottle.properties.AlarmProperties;
import com.zd.bottle.service.AlarmRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zd.bottle.service.BottleStorageService;
import com.zd.bottle.service.RfidTagService;
import com.zd.bottle.service.UsegasApplyService;
import com.zd.bottle.vo.AlarmRecordVo;
import com.zd.bottle.vo.BottleStorageVo;
import com.zd.common.core.constant.HttpStatus;
import com.zd.common.core.domain.R;
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.domain.SysFile;
import com.zd.system.api.forward.RemoteForwardService;
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.apache.poi.util.StringUtil;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

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;

/**
 * <p>
 * 报警记录表 服务实现类
 * </p>
 *
 * @author hanson
 * @since 2022-09-08
 */
@Service
@Slf4j
public class AlarmRecordServiceImpl extends ServiceImpl<AlarmRecordMapper, AlarmRecord> implements AlarmRecordService {

    @Resource
    private BottleStorageService storageService;

    private static final String FRID_CODE = "FRID:";
    @Resource
    private RemoteNettyService remoteNettyService;
    @Resource
    private RedisService redisService;
    @Resource
    private RemoteUserService userService;
    @Resource
    private RemoteLaboratoryService laboratoryService;
    @Resource
    private RemoteAlarmService remoteAlarmService;
    @Resource
    private RemoteSubQueryService remoteSubQueryService;

    @Resource
    private RfidTagService tagService;

    @Resource
    private UsegasApplyService applyService;

    @Resource
    private RemoteForwardService remoteForwardService;

    @Resource
    private AlarmProperties alarmProperties;

    private static final String MSG_MATCH = "==================>{},{}";

    @Override
    public void getRecordInfo(List<AlarmRecordVo> recordVos) {
        List<Long> masterIds = recordVos.stream().filter(alarmRecordVo -> alarmRecordVo.getProductType() == 1).map(AlarmRecordVo::getMasterId).collect(Collectors.toList());
        List<BottleStorage> storages = storageService.listByIds(masterIds);
        Map<Long, BottleStorage> storageMap = storages.stream().collect(Collectors.toMap(BottleStorage::getId, s -> s));
        recordVos.forEach(r -> {
            Long masterId = r.getMasterId();
            if (storageMap.containsKey(masterId)) {
                BottleStorage storage = storageMap.get(masterId);
                r.setCurrentPressure(storage.getCurrentPressure())
                        .setAirName(storage.getAirName())
                        .setConfigName(storage.getConfigName())
                        .setAirNumber(storage.getAirNumber());
            }
        });
    }

    @Override
    public List<AlarmRecord> getList(AlarmRecord alarmRecord) {
        LambdaQueryWrapper<AlarmRecord> queryWrapper = Wrappers.lambdaQuery(AlarmRecord.class);
        String startTime = alarmRecord.getStartTime();
        String endTime = alarmRecord.getEndTime();
        queryWrapper.apply(StringUtils.hasLength(startTime), "DATE_FORMAT(alarm_time,'%Y-%m-%d') >=date_format('" + startTime + "','%Y-%m-%d')")
                .apply(StringUtils.hasLength(startTime), "DATE_FORMAT(alarm_time,'%Y-%m-%d') <=date_format('" + endTime + "','%Y-%m-%d')");
        return list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized boolean remoteAdd(InventoryTag tag) {
        String electronicTag = tag.getEpc();
        RemoteLabHardware hardware = tag.getRemoteLabHardware();
        LambdaQueryWrapper<RfidTag> queryWrapper = Wrappers.lambdaQuery(RfidTag.class);
        queryWrapper.eq(RfidTag::getTagCode, electronicTag);
        RfidTag rfidTag = tagService.getOne(queryWrapper);
        if (rfidTag == null) {
            log.info(MSG_MATCH, electronicTag, "标签未录入");
            return false;
        }
        LambdaQueryWrapper<BottleStorage> wrapper = Wrappers.lambdaQuery(BottleStorage.class);
        wrapper.eq(BottleStorage::getElectronicTag, rfidTag.getAuthCode());
        BottleStorage bottleStorage = storageService.getOne(wrapper);
        if (bottleStorage != null) {
            String airName = bottleStorage.getAirName();
            LambdaQueryWrapper<UsegasApply> lambdaQuery = Wrappers.lambdaQuery(UsegasApply.class);
            lambdaQuery.eq(UsegasApply::getUseGasName, airName)
                    .ge(UsegasApply::getEndTime, DateUtil.formatDate(Calendar.getInstance().getTime())).eq(UsegasApply::getLeadAuditStaus, 1);
            List<UsegasApply> applies = applyService.list(lambdaQuery);
            if (applies.isEmpty()) {
                Long id = bottleStorage.getId();
                R<SysFile> fileR = getFileR(tag, hardware);
                String key = FRID_CODE + electronicTag + id;
                String frid = redisService.getCacheObject(key);
                if (frid != null) {
                    return true;
                }
                // 发送报警消息
                sendAlarm(bottleStorage);
                redisService.setCacheObject(key, electronicTag, 300L, TimeUnit.SECONDS);
                AlarmRecord alarmRecord = new AlarmRecord();
                if (fileR != null && fileR.getCode() == HttpStatus.SUCCESS && fileR.getData() != null) {
                    SysFile data = fileR.getData();
                    alarmRecord.setAttachmentUrl(data.getUrl());
                }
                alarmRecord.setElectronicTag(electronicTag)
                        .setAlarmTime(Calendar.getInstance().getTime())
                        .setMasterId(id)
                        .setType(1)
                        .setProductType(1)
                        .setDeptId(bottleStorage.getDeptId());
                return save(alarmRecord);
            }
        } else {
            if (hardware != null) {
                log.info(MSG_MATCH, electronicTag, "标签未绑定气瓶");
            }
        }
        return false;
    }

    @Nullable
    private R<SysFile> getFileR(InventoryTag tag, RemoteLabHardware hardware) {
        //触发RFID警报
        if (hardware != null) {
            R<Boolean> alarm = remoteNettyService.alarm(hardware);//RFID设备报警
            log.info(MSG_MATCH, alarm.getCode(), alarm.getMsg());
        } else {
            log.info("==================> rfid 参数有误！" + tag);
        }
        String streamUrl = alarmProperties.getStreamUrl();
        if (StringUtils.hasLength(streamUrl)) {
            R<SysFile> fileR = remoteForwardService.photograph(alarmProperties.getStreamUrl());
            log.info("文件上传状态：{}，接口返回消息：{}，文件上传路径：{}", fileR.getCode(), fileR.getMsg(), fileR.getData());
            return fileR;
        }
        return null;
    }

    private void sendAlarm(BottleStorage storage) {
        Long subjectId = storage.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);
                //发送电话警报
                sendPhone(storage, 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(BottleStorage storage, 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 airName = storage.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, storage.getSubjectId(), phones);
        }
    }

}
