package com.multictrl.common.task;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Maps;
import com.multictrl.common.utils.DateUtils;
import com.multictrl.common.utils.Spatial4jUtils;
import com.multictrl.modules.business.dao.FlightTaskDao;
import com.multictrl.modules.business.entity.FlightTaskEntity;
import com.multictrl.modules.business.entity.MediaFileEntity;
import com.multictrl.modules.business.influxdb.UavReport;
import com.multictrl.modules.business.service.FlightTaskService;
import com.multictrl.modules.business.service.InfluxService;
import com.multictrl.modules.business.service.MediaFileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 航线任务矫正
 *
 * @author Sdy
 * @since 1.0.0 2025/5/29
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class FlightTaskUpdate {
    private final InfluxService influxService;
    private final MediaFileService mediaFileService;
    private final FlightTaskService flightTaskService;
    private final FlightTaskDao flightTaskDao;

    @Scheduled(fixedRate = 60 * 1000) // 每 60秒执行一次（单位：毫秒）
    public void updateFlightTask() {
        Date threeHoursAgo = DateUtil.offsetHour(new Date(), -3);
        LambdaQueryWrapper<FlightTaskEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.gt(FlightTaskEntity::getCreateDate, threeHoursAgo)
                .and(wrapper2 -> wrapper2
                        .isNull(FlightTaskEntity::getTaskStatus)
                        .or()
                        .eq(FlightTaskEntity::getTaskStatus, 0)
                        .or()
                        .isNull(FlightTaskEntity::getFlightDistance)
                        .or()
                        .isNull(FlightTaskEntity::getFlightDuration)
                        .or()
                        .isNull(FlightTaskEntity::getMediaNum)
                        .or()
                        .eq(FlightTaskEntity::getMediaNum, 0)
                );
        List<FlightTaskEntity> taskList = flightTaskDao.selectList(wrapper);
        Map<String, FlightTaskEntity> updateMap = new HashMap<>();
        for (FlightTaskEntity entity : taskList) {
            Date createDate = entity.getCreateDate();
            long createMillis = createDate.getTime();
            long diffSeconds = Math.abs((new Date().getTime() - createMillis) / 1000);
            // 1. 处理状态字段
            handleStatus(entity, diffSeconds, updateMap);
            // 2. 处理飞行距离
            handleFlightDistance(entity, diffSeconds, updateMap);
            // 3. 处理飞行时长
            handleFlightDuration(entity, diffSeconds, updateMap);
            // 4. 处理媒体数量
            handleMediaNum(entity, diffSeconds, updateMap);
        }
        if (!updateMap.isEmpty()) {
            flightTaskService.updateBatchById(new ArrayList<>(updateMap.values()));
        }
    }

    private void handleStatus(FlightTaskEntity entity, long diffSeconds, Map<String, FlightTaskEntity> updateMap) {
        if (entity.getTaskStatus() == null || entity.getTaskStatus() == 0) {
            if (entity.getFailureReason() != null) {
                entity.setTaskStatus(-1);
                updateMap.put(entity.getTaskId(), entity);
            } else if (entity.getInboundDate() != null) {
                entity.setTaskStatus(1);
                updateMap.put(entity.getTaskId(), entity);
            } else if (diffSeconds > 7200) {
                entity.setTaskStatus(-1);
                updateMap.put(entity.getTaskId(), entity);
            } else if (entity.getTaskStatus() == null) {
                entity.setTaskStatus(0);
                updateMap.put(entity.getTaskId(), entity);
            }
        }
    }

    private void handleFlightDistance(FlightTaskEntity entity, long diffSeconds, Map<String, FlightTaskEntity> updateMap) {
        if (entity.getFlightDistance() == null) {
            if (entity.getOutboundDate() != null && entity.getInboundDate() != null) {
                entity.setFlightDistance(getFlightDistance(entity.getDockSn(), entity.getOutboundDate(), entity.getInboundDate()));
                updateMap.put(entity.getTaskId(), entity);
            } else if (diffSeconds > 7200) {
                if (entity.getInboundDate() != null) {
                    entity.setFlightDistance(getFlightDistance(entity.getDockSn(), entity.getCreateDate(), entity.getInboundDate()));
                    updateMap.put(entity.getTaskId(), entity);
                } else if (entity.getOutboundDate() != null) {
                    entity.setFlightDistance(getFlightDistance(entity.getDockSn(), entity.getOutboundDate(),
                            DateUtils.getBeforeHour(entity.getOutboundDate(), 1)));
                    updateMap.put(entity.getTaskId(), entity);
                } else {
                    entity.setFlightDistance(getFlightDistance(entity.getDockSn(), entity.getCreateDate(),
                            DateUtils.getBeforeHour(entity.getCreateDate(), 1)));
                    updateMap.put(entity.getTaskId(), entity);
                }
            }
        }
    }

    //获取飞行距离
    private double getFlightDistance(String dockSn, Date startDate, Date endDate) {
        HashMap<String, Object> condition = Maps.newHashMap();
        condition.put("dockSn", dockSn);
        List<UavReport> flyList = influxService.queryData(DateUtils.format(startDate, DateUtils.DATE_TIME_PATTERN),
                DateUtils.format(endDate, DateUtils.DATE_TIME_PATTERN), "uav_osd", condition, UavReport.class,
                "longitude", "latitude", "elevation", "_time");
        double total = 0;
        for (int i = 0; i < flyList.size() - 1; i++) {
            UavReport p1 = flyList.get(i);
            UavReport p2 = flyList.get(i + 1);
            total += Spatial4jUtils.distance(p1.getLatitude(), p1.getLongitude(), p2.getLatitude(), p2.getLongitude());
        }

        return total;
    }

    private void handleFlightDuration(FlightTaskEntity entity, long diffSeconds, Map<String, FlightTaskEntity> updateMap) {
        if (entity.getFlightDuration() == null) {
            if (entity.getOutboundDate() != null && entity.getInboundDate() != null) {
                setFlightDuration(entity, entity.getOutboundDate(), entity.getInboundDate());
                updateMap.put(entity.getTaskId(), entity);
            } else if (diffSeconds > 7200) {
                if (entity.getInboundDate() != null) {
                    setFlightDuration(entity, entity.getCreateDate(), entity.getInboundDate());
                    updateMap.put(entity.getTaskId(), entity);
                } else if (entity.getOutboundDate() != null) {
                    setFlightDuration(entity, entity.getOutboundDate(),
                            DateUtils.getBeforeHour(entity.getOutboundDate(), 1));
                    updateMap.put(entity.getTaskId(), entity);
                } else {
                    setFlightDuration(entity, entity.getCreateDate(),
                            DateUtils.getBeforeHour(entity.getCreateDate(), 1));
                    updateMap.put(entity.getTaskId(), entity);
                }
            }
        }
    }

    //设置飞行时间
    private void setFlightDuration(FlightTaskEntity entity, Date startTime, Date endTime) {
        HashMap<String, Object> condition = Maps.newHashMap();
        condition.put("dockSn", entity.getDockSn());
        List<UavReport> flyList = influxService.queryData(DateUtils.format(startTime, DateUtils.DATE_TIME_PATTERN),
                DateUtils.format(endTime, DateUtils.DATE_TIME_PATTERN), "uav_osd", condition, UavReport.class,
                "longitude", "latitude", "elevation", "_time");

        UavReport start = null;
        UavReport end = null;
        for (int i = 0; i < flyList.size() - 1; i++) {
            //过滤出起飞和降落的记录，当飞机和机场的相对高度大于0，则认为飞机在飞行中，开始计算飞行时长
            if (flyList.get(i).getElevation() > 0) {
                end = flyList.get(i);
                if (start == null) {
                    start = flyList.get(i);
                }
            }
        }
        String flightDurationText = "0秒";
        long flightDuration = 0L;
        if (start != null && end != null) {
            DateTime startDate = DateUtil.parseDateTime(start.getTimeStr());
            DateTime endDate = DateUtil.parseDateTime(end.getTimeStr());
            flightDurationText = DateUtils.formatDifference(startDate, endDate);
            flightDuration = Math.abs((endDate.getTime() - startDate.getTime()) / 1000);
        }
        entity.setFlightDurationText(flightDurationText);
        entity.setFlightDuration(flightDuration);
    }

    private void handleMediaNum(FlightTaskEntity entity, long diffSeconds, Map<String, FlightTaskEntity> updateMap) {
        if ((entity.getMediaNum() == null || entity.getMediaNum() == 0) && diffSeconds > 7200) {
            Long count = mediaFileService.getDao().selectCount(new QueryWrapper<MediaFileEntity>()
                    .eq("task_id", entity.getTaskId()).eq("dock_sn", entity.getDockSn()));
            entity.setMediaNum(count.intValue());
            updateMap.put(entity.getTaskId(), entity);
        }
    }
}
