package com.aiotagro.cattletrade.business.service.impl;

import com.aiotagro.cattletrade.business.dto.DeliveryQueryDto;
import com.aiotagro.cattletrade.business.dto.WarningDetailDto;
import com.aiotagro.cattletrade.business.entity.Delivery;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.aiotagro.cattletrade.business.entity.JbqServerLog;
import com.aiotagro.cattletrade.business.entity.WarningLog;
import com.aiotagro.cattletrade.business.mapper.DeliveryDeviceMapper;
import com.aiotagro.cattletrade.business.mapper.DeliveryMapper;
import com.aiotagro.cattletrade.business.mapper.JbqServerLogMapper;
import com.aiotagro.cattletrade.business.mapper.WarningLogMapper;
import com.aiotagro.cattletrade.business.service.IWarningLogService;
import com.aiotagro.cattletrade.business.vo.DeliveryLogVo;
import com.aiotagro.cattletrade.constant.WarningStatusAdminEnum;
import com.aiotagro.cattletrade.constant.WarningStatusEnum;
import com.aiotagro.common.core.utils.EnumUtil;
import com.aiotagro.common.core.utils.LngLonUtil;
import com.aiotagro.common.core.utils.SecurityUtil;
import com.aiotagro.common.core.utils.StringUtils;
import com.aiotagro.common.core.utils.uuid.DistinctUtil;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 预警记录表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2024-12-26
 */
@Service
@Slf4j
public class WarningLogServiceImpl extends ServiceImpl<WarningLogMapper, WarningLog> implements IWarningLogService {


    @Autowired
    private WarningLogMapper warningLogMapper;
    @Autowired
    private DeliveryMapper deliveryMapper;
    @Autowired
    private DeliveryDeviceMapper deliveryDeviceMapper;
    @Autowired
    private JbqServerLogMapper serverLogMapper;

    /**
     * 预警统计
     *
     * @return
     */
    @Override
    public AjaxResult warningCount() {
        //获取当前登录人信息
        Integer currentUserId = SecurityUtil.getCurrentUserId();
        //返回结果集
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("checkCount", 0);
        resMap.put("rangeCount", 0);
        DeliveryQueryDto deliveryQueryDto = new DeliveryQueryDto();
        deliveryQueryDto.setUserId(currentUserId);
        //查询最新的一条上报数据的预警记录结果
        List<WarningLog> newWarningLog = warningLogMapper.getNewWarningLog(deliveryQueryDto);
        if (CollectionUtils.isNotEmpty(newWarningLog)) {
            //数量盘点预警
            long checkCount = newWarningLog.stream().filter(warningLog -> "2".equals(warningLog.getWarningType())).count();
            long rangeCount = newWarningLog.stream().filter(warningLog -> "3".equals(warningLog.getWarningType())).count();
            resMap.put("checkCount", checkCount);
            resMap.put("rangeCount", rangeCount);
        }
        return AjaxResult.success("查询成功", resMap);
    }

    @Override
    public PageResultResponse<DeliveryLogVo> queryList(DeliveryQueryDto dto) {
        //返回结果集对象
        List<DeliveryLogVo> resList = new ArrayList<>();
        Page<Delivery> result = PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        dto.setUserId(SecurityUtil.getCurrentUserId());//当前登录人
        List<WarningLog> newWarningLog = warningLogMapper.getNewWarningLog(dto);
        if (CollectionUtils.isNotEmpty(newWarningLog)) {
            List<Integer> deliveryIds = newWarningLog.stream().map(WarningLog::getDeliveryId).collect(Collectors.toList());
            //根据运单id查询运单的信息
            List<Delivery> deliveryList = deliveryMapper.selectBatchIds(deliveryIds);
            if (CollectionUtils.isNotEmpty(deliveryList)) {
                Map<Integer, Delivery> deliveryMap = deliveryList.stream().collect(Collectors.toMap(Delivery::getId, delivery -> delivery));
                newWarningLog.forEach(warningLog -> {
                    Delivery delivery = deliveryMap.get(warningLog.getDeliveryId());
                    if (delivery != null) {
                        DeliveryLogVo deliveryLogVo = new DeliveryLogVo();
                        deliveryLogVo.setId(warningLog.getId());
                        deliveryLogVo.setLicensePlate(delivery.getLicensePlate());
                        deliveryLogVo.setDeliveryId(warningLog.getDeliveryId());
                        deliveryLogVo.setDeliveryNumber(delivery.getDeliveryNumber());
                        deliveryLogVo.setStatus(delivery.getStatus());
                        deliveryLogVo.setStatusDesc(2 == delivery.getStatus() ? "已核验" : "待核验");
                        deliveryLogVo.setCarFrontPhoto(delivery.getCarFrontPhoto());
                        deliveryLogVo.setRegisteredJbqCount(delivery.getRegisteredJbqCount());
                        deliveryLogVo.setInventoryJbqCount(warningLog.getInventoryJbqCount());
                        deliveryLogVo.setActualDistance(warningLog.getActualDistance());
                        deliveryLogVo.setExpectedDistance(warningLog.getExpectedDistance());
                        String warningType = warningLog.getWarningType();
                        deliveryLogVo.setWarningType(warningType);
                        if (StringUtils.isNotEmpty(warningType)) {
                            deliveryLogVo.setWarningTypeDesc(EnumUtil.getEnumConstant(WarningStatusAdminEnum.class , Integer.parseInt(warningType)).getDescription());
                        }
                        deliveryLogVo.setWarningTime(warningLog.getWarningTime());
                        resList.add(deliveryLogVo);
                    }
                });
            }
        }
        return new PageResultResponse(result.getTotal(), resList);
    }

    @Override
    public AjaxResult warningDetail(Integer id) {
        WarningDetailDto warningDetailDto = new WarningDetailDto();
        //预警记录信息
        WarningLog warningLog = warningLogMapper.selectById(id);
        BeanUtils.copyProperties(warningLog, warningDetailDto);
        String warningType = warningLog.getWarningType();
        if (StringUtils.isNotEmpty(warningType)) {
            warningDetailDto.setWarningReason(EnumUtil.getEnumConstant(WarningStatusEnum.class , Integer.parseInt(warningType)).getDescription());
        }
        //获取当前记录的运单信息
        Delivery delivery = deliveryMapper.selectById(warningLog.getDeliveryId());
        BeanUtils.copyProperties(delivery, warningDetailDto);
        warningDetailDto.setWarningTime(warningLog.getWarningTime());
        warningDetailDto.setWarningType(warningType);
        warningDetailDto.setInventoryJbqCount(warningLog.getInventoryJbqCount());
        //获取当前运单关联的设备信息
        List<DeliveryDevice> deliveryDevices = deliveryDeviceMapper.selectList(new LambdaQueryWrapper<DeliveryDevice>().eq(DeliveryDevice::getDeliveryId, delivery.getId()));
        if (CollectionUtils.isNotEmpty(deliveryDevices)) {
            List<String> serverCollect = deliveryDevices.stream().filter(deliveryDevice -> deliveryDevice.getDeviceType() == 1).map(DeliveryDevice::getDeviceId).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(serverCollect)) {
                warningDetailDto.setServerDeviceSn(serverCollect.get(0));
            }
            List<String> jbqDeviceCollect = deliveryDevices.stream().filter(deliveryDevice -> deliveryDevice.getDeviceType() == 2).map(DeliveryDevice::getDeviceId).collect(Collectors.toList());
            warningDetailDto.setJbqDeviceSn(jbqDeviceCollect);
        }
        return AjaxResult.success(warningDetailDto);
    }

    @Override
    public AjaxResult savaWarn(String deviceId) {
        // 查询主机关联的最新运单
        List<DeliveryDevice> list = deliveryDeviceMapper.selectList(new LambdaQueryWrapper<DeliveryDevice>().eq(DeliveryDevice::getDeviceId, deviceId)
                .orderByDesc(DeliveryDevice::getId));
        // 主机未绑定运单 无需操作
        if (CollectionUtils.isEmpty(list)) {
            return AjaxResult.success();
        }
        Delivery delivery = deliveryMapper.selectById(list.get(0).getDeliveryId());
        // 运单已核验 无需操作
        if (delivery.getStatus() == 2) {
            return AjaxResult.success();
        }

        // 查询运单创建后的主机上报日志
        List<JbqServerLog> logs = serverLogMapper.selectList(new LambdaQueryWrapper<JbqServerLog>().eq(JbqServerLog::getDeviceId, deviceId)
                .ge(JbqServerLog::getCreateTime, delivery.getCreateTime()).orderByDesc(JbqServerLog::getCreateTime));
        LocalDateTime endTime = logs.get(0).getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        LocalDateTime createTime;
        Double endLat = Double.parseDouble(logs.get(0).getLatitude());
        Double endLon = Double.parseDouble(logs.get(0).getLongitude());
        // 转换成高德经纬度
        double[] gcjDouble = LngLonUtil.gps84_To_Gcj02(endLat, endLon);
        endLat = gcjDouble[0];
        endLon = gcjDouble[1];
        Double startLat;
        Double startLon;
        if (logs.size() == 1) {
            // 第一次上报 计算上报时间到运单创建时间的时间段
            createTime = delivery.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
            // 腾讯地图经纬度无需转换
            startLat = Double.parseDouble(delivery.getStartLat());
            startLon = Double.parseDouble(delivery.getStartLon());
        } else {
            // 多次上报 计算上报时间到上一次上报时间的时间段
            createTime = logs.get(1).getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
            startLat = Double.parseDouble(logs.get(1).getLatitude());
            startLon = Double.parseDouble(logs.get(1).getLongitude());
            // 转换成高德经纬度
            double[] gcjDouble1 = LngLonUtil.gps84_To_Gcj02(startLat, startLon);
            startLat = gcjDouble1[0];
            startLon = gcjDouble1[1];
        }

        // 计算时间差，单位为小时
        double hoursBetween = Duration.between(createTime, endTime).toMinutes() / 60.0;
        // 确定当前上报时间是在白天还是晚上
        boolean isDayTime = !endTime.toLocalTime().isBefore(LocalTime.of(8, 0)) &&
                !endTime.toLocalTime().isAfter(LocalTime.of(20, 0));
        // 计算基准距离
        double baseDistance = isDayTime ? (80 * hoursBetween * 0.9) : (80 * hoursBetween * 0.8);
        // 四舍五入 保留3位小数
        baseDistance = BigDecimal.valueOf(baseDistance).setScale(3, RoundingMode.HALF_UP).doubleValue();
        // 计算本次上报点 和上次上报点之间的经纬度导航实际距离 km
        try {
            double distance = DistinctUtil.calculateDistance(startLat, startLon, endLat, endLon);
            // 小于基准距离 发起预警
            WarningLog log = new WarningLog();
            log.setWarningTime(new Date());
            if (distance < baseDistance) {
                log.setWarningType("3");
            } else {
                log.setWarningType("1");
            }
            log.setDeliveryId(delivery.getId());
            log.setActualDistance(String.valueOf(distance));
            log.setExpectedDistance(String.valueOf(baseDistance));
            save(log);
        } catch (Exception e) {
            log.error("请求高德api计算距离失败：", e);
            return AjaxResult.error("请求高德api计算距离失败");
        }
        return AjaxResult.success();
    }

}
