package com.yida.data.device.studentCard.config;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.rabbitmq.client.Channel;
import com.yida.data.common.core.entity.card.EduStudentCard;
import com.yida.data.common.core.entity.card.EduStudentCardAlarm;
import com.yida.data.common.core.entity.card.EduStudentCardFence;
import com.yida.data.common.core.entity.constant.AppConstant;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.notice.qywx.TextSchoolNotice;
import com.yida.data.common.core.entity.notice.qywx.inside.Text;
import com.yida.data.common.core.entity.system.EduApp;
import com.yida.data.common.core.entity.user.EduStudent;
import com.yida.data.common.core.enums.CardAlarmType;
import com.yida.data.common.core.utils.GeoUtil;
import com.yida.data.common.core.utils.WxUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.device.dto.studentCard.CardMsgDTO;
import com.yida.data.device.studentCard.mapper.EduStudentCardFenceMapper;
import com.yida.data.device.studentCard.service.EduStudentCardAlarmService;
import com.yida.data.device.studentCard.service.EduStudentCardService;
import com.yida.data.device.vo.studentCard.LocationVO;
import com.yida.data.rabbit.constant.RabbitConstant;
import com.yida.data.user.feign.RemoteStudentService;
import java.io.IOException;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@AllArgsConstructor
public class CardRabbitReceiver {

    private final EduStudentCardService eduStudentCardService;
    private final EduStudentCardFenceMapper eduStudentCardFenceMapper;
    private final EduStudentCardAlarmService eduStudentCardAlarmService;
    private final RemoteStudentService remoteStudentService;
    private final RedisService redisService;
    private final WxUtil wxUtil;
    private final CommonService commonService;

    @RabbitListener(bindings = @QueueBinding(
        value = @Queue(RabbitConstant.CARD_810A_MSG_QUEUE),
        exchange = @Exchange(RabbitConstant.CARD_EXCHANGE)
    ))
    public void receivePosition(CardMsgDTO reportMsg, Channel channel, Message message) {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            if (CardMsgDTO.STEP.equals(reportMsg.getMsgType())) { //步数
                dealStep(reportMsg);
            } else if (CardMsgDTO.LOCATION.equals(reportMsg.getMsgType())) { //定位点上传
                boolean isConsume = false;
                Long time = reportMsg.getDeviceTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
                Long lastTime = (Long) redisService
                    .hget(CachePrefixConstant.DEVICE_CARD_LAST_CONSUME_MSG, reportMsg.getImei());
                if (lastTime != null && time <= lastTime) {
                    isConsume = true;
                }
                if (!isConsume) {
                    // 更新学生证最新定位消息
                    redisService.hset(CachePrefixConstant.DEVICE_CARD_LAST_CONSUME_MSG, reportMsg.getImei(), time);
                    // 缓存定位数据
                    LocationVO locationVO = new LocationVO();
                    BeanUtils.copyProperties(reportMsg, locationVO);
                    redisService.hset(CachePrefixConstant.DEVICE_CARD_LATEST_LOCATION, reportMsg.getImei(), locationVO);
                    // 围栏告警判断
                    if (reportMsg.getLng() != null && reportMsg.getLat() != null) {
                        dealFenceAlarm(reportMsg);
                    }
                }
            } else if (CardMsgDTO.RISK_AREA.equals(reportMsg.getMsgType())) { // 危险区域上报
                dealRiskArea(reportMsg);
            } else if (CardMsgDTO.LOW_BAT.equals(reportMsg.getMsgType())) {// 低电量推送
                LocationVO location = (LocationVO) redisService
                    .hget(CachePrefixConstant.DEVICE_CARD_LATEST_LOCATION, reportMsg.getImei());
                if (location != null) {
                    location.setBat(reportMsg.getBat());
                    redisService.hset(CachePrefixConstant.DEVICE_CARD_LATEST_LOCATION, reportMsg.getImei(), location);
                }
                dealLowBatAlarm(reportMsg);
            } else if (CardMsgDTO.DEVICE_STATIC.equals(reportMsg.getMsgType())) { //设备脱落
                dealDeviceStatic(reportMsg);
            }
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
            log.error("签收失败", e);
            try {
                channel.basicNack(deliveryTag, false, false);
            } catch (IOException exception) {
                log.error("拒签失败", exception);
            }
        }

    }

    private void pushMsg(String imei, String msg) {
        EduStudentCard card = eduStudentCardService
            .getOne(Wrappers.<EduStudentCard>lambdaQuery().eq(EduStudentCard::getImei, imei));
        EduStudent student = (EduStudent) redisService
            .hget(CachePrefixConstant.STUDENT_DATA, card.getStudentId().toString());
        if (student == null) {
            student = remoteStudentService.getStudentNoPermission(card.getStudentId()).getData();
            if (student == null) {
                return;
            }
            redisService.hset(CachePrefixConstant.STUDENT_DATA, card.getStudentId().toString(), student);
        }
        EduApp app = commonService
            .getAppByCodeAndSchool(AppConstant.INDEX_PARENT, null, card.getSchoolId());
        String accessToken = wxUtil.getAccessToken(app.getWxCorpId(), app.getWxSecret());
        TextSchoolNotice notice = new TextSchoolNotice();
        notice.setAgentid(app.getWxAgentId());
        notice.setTo_student_userid(Collections.singletonList(student.getWxId()));
        notice.setText(new Text(msg.replace("{name}", student.getStuName())));
        wxUtil.pushSchoolNotice(accessToken, notice);
    }

    private void dealFenceAlarm(CardMsgDTO dto) {
        List<Object> list = redisService.lGet(CachePrefixConstant.DEVICE_CARD_FENCE_DATA + dto.getImei(), 0L, -1L);
        List<EduStudentCardFence> fenceList;
        if (CollUtil.isNotEmpty(list)) {
            fenceList = list.stream().map(x -> (EduStudentCardFence) x).collect(Collectors.toList());
        } else {
            // 查询之后入缓存
            fenceList = eduStudentCardFenceMapper.listFenceByImei(dto.getImei());
            if (CollUtil.isEmpty(fenceList)) {
                fenceList = Collections.singletonList(null);
            }
            redisService.llSet(CachePrefixConstant.DEVICE_CARD_FENCE_DATA + dto.getImei(), fenceList);
        }
        // 第一个元素未空  该学生未创建围栏   不做处理
        if (fenceList.get(0) == null) {
            return;
        }
        // 学生证数据
        EduStudentCard studentCard = (EduStudentCard) redisService
            .hget(CachePrefixConstant.DEVICE_CARD_DATA, dto.getImei());
        if (studentCard == null) {
            studentCard = eduStudentCardService.getOne(Wrappers.<EduStudentCard>lambdaQuery()
                .eq(EduStudentCard::getImei, dto.getImei()));
            if (studentCard == null) {
                return;
            }
            redisService.hset(CachePrefixConstant.DEVICE_CARD_DATA, studentCard.getImei(), studentCard);
        }
        // 查询告警围栏
        for (EduStudentCardFence fence : fenceList) {
            // 到圆心距离
            Double distance = GeoUtil.getDistance(fence.getLng(), fence.getLat(), dto.getLng(), dto.getLat());
            Integer status = (Integer) redisService
                .hget(CachePrefixConstant.DEVICE_CARD_FENCE_STATUS + dto.getImei(), fence.getId().toString());
            // 状态未改变
            if (status != null && ((status == 0 && distance < fence.getRadius())
                || (status == 1 && distance > fence.getRadius()))) {
                continue;
            }
            status = distance > fence.getRadius() ? 1 : 0;
            redisService.hset(CachePrefixConstant.DEVICE_CARD_FENCE_STATUS + dto.getImei(), fence.getId().toString(), status);
            // 推送告警信息
            log.info("触发告警,当前位置:[{},{}],围栏位置:[{},{}],距离:[{}]", dto.getLng(), dto.getLat(), fence.getLng(),
                fence.getLat(), distance);
            EduStudentCardAlarm alarm = new EduStudentCardAlarm();
            alarm.setImei(dto.getImei());
            alarm.setAlarmType(status == 0 ? CardAlarmType.IN_FENCE.getValue() : CardAlarmType.OUT_FENCE.getValue());
            alarm.setLng(dto.getLng());
            alarm.setLat(dto.getLat());
            alarm.setAlarmTime(dto.getDeviceTime());
            alarm.setRemark(fence.getName());
            alarm.setRemarkValue(fence.getId().toString());
            alarm.setAddress(dto.getAddress());
            eduStudentCardAlarmService.saveAlarm(alarm);
        }
    }

    private void dealLowBatAlarm(CardMsgDTO dto) {
//        Integer lastBat = (Integer) redisService
//            .hget(CachePrefixConstant.DEVICE_CARD_LOWBAT_VALUE, dto.getImei());
        int thisBat = ((dto.getBat() % 5) + 1) * 5;
//        if (thisBat != lastBat) {
//        redisService.hset(CachePrefixConstant.DEVICE_CARD_LOWBAT_VALUE, dto.getImei(), thisBat);
        EduStudentCardAlarm alarm = new EduStudentCardAlarm();
        alarm.setImei(dto.getImei());
        alarm.setRemark(Integer.toString(thisBat));
        alarm.setLng(dto.getLng());
        alarm.setLat(dto.getLat());
        alarm.setAlarmType(CardAlarmType.LOW_BAT.getValue());
        alarm.setAlarmTime(dto.getDeviceTime());
        alarm.setRemarkValue(dto.getBat().toString());
        eduStudentCardAlarmService.saveAlarm(alarm);
//        }
    }

    private void dealRiskArea(CardMsgDTO dto) {
        EduStudentCardAlarm alarm = new EduStudentCardAlarm();
        alarm.setImei(dto.getImei());
        alarm.setAlarmType(CardAlarmType.RISK_AREA.getValue());
        alarm.setLng(dto.getLng());
        alarm.setLat(dto.getLat());
        alarm.setAlarmTime(dto.getDeviceTime());
        alarm.setAddress(dto.getAddress());
        alarm.setRemarkValue(dto.getRemark());
        eduStudentCardAlarmService.saveAlarm(alarm);
    }

    private void dealStep(CardMsgDTO dto) {
        EduStudentCardAlarm alarm = new EduStudentCardAlarm();
        alarm.setImei(dto.getImei());
        alarm.setAlarmType(CardAlarmType.STEP.getValue());
        alarm.setLng(dto.getLng());
        alarm.setLat(dto.getLat());
        alarm.setAlarmTime(dto.getDeviceTime());
        alarm.setAddress(dto.getAddress());
        alarm.setRemarkValue(dto.getStep().toString());
        eduStudentCardAlarmService.saveAlarm(alarm);
    }

    private void dealDeviceStatic(CardMsgDTO dto) {
        EduStudentCardAlarm alarm = new EduStudentCardAlarm();
        alarm.setImei(dto.getImei());
        alarm.setAlarmType(CardAlarmType.DEVICE_STATIC.getValue());
        alarm.setLng(dto.getLng());
        alarm.setLat(dto.getLat());
        alarm.setAlarmTime(dto.getDeviceTime());
        alarm.setAddress(dto.getAddress());
        alarm.setRemarkValue(dto.getStep().toString());
        eduStudentCardAlarmService.saveAlarm(alarm);
    }
}
