package com.qaup.system.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.concurrent.atomic.AtomicLong;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.qaup.common.utils.GeoUtils;
import com.qaup.system.mapper.SysVehicleLocationMapper;
import com.qaup.system.domain.SysVehicleLocation;
import com.qaup.system.domain.vo.VehicleTrajectoryVO;
import com.qaup.system.domain.vo.VehicleLocationPlaybackVO;
import com.qaup.system.domain.vo.TrajectoryStatistics;
import com.qaup.system.domain.vo.TrajectoryPoint;
import com.qaup.system.domain.dto.TrajectoryQueryRequest;
import com.qaup.system.service.ISysVehicleLocationService;

/**
 * 车辆运动信息Service业务层处理
 * 
 * @author qaup
 * @date 2025-01-16
 */
@Service
public class SysVehicleLocationServiceImpl implements ISysVehicleLocationService {
    @Autowired
    private SysVehicleLocationMapper sysVehicleLocationMapper;

    /**
     * 查询车辆运动信息列表
     * 
     * @param sysVehicleLocation 车辆运动信息
     * @return 车辆运动信息
     */
    @Override
    public List<SysVehicleLocation> selectSysVehicleLocationList(SysVehicleLocation sysVehicleLocation) {
        return sysVehicleLocationMapper.selectSysVehicleLocationList(sysVehicleLocation);
    }

    /**
     * 根据车辆ID查询车辆运动信息
     * 
     * @param vehicleId 车辆ID
     * @return 车辆运动信息列表
     */
    @Override
    public List<SysVehicleLocation> selectSysVehicleLocationByVehicleId(Long vehicleId) {
        return sysVehicleLocationMapper.selectSysVehicleLocationByVehicleId(vehicleId);
    }

    /**
     * 根据车牌号查询车辆运动信息
     * 
     * @param licensePlate 车牌号
     * @return 车辆运动信息列表
     */
    @Override
    public List<SysVehicleLocation> selectSysVehicleLocationByLicensePlate(String licensePlate) {
        return sysVehicleLocationMapper.selectSysVehicleLocationByLicensePlate(licensePlate);
    }

    /**
     * 查询车辆最新位置信息
     * 
     * @param vehicleId 车辆ID
     * @return 车辆运动信息
     */
    @Override
    public SysVehicleLocation selectLatestSysVehicleLocationByVehicleId(Long vehicleId) {
        return sysVehicleLocationMapper.selectLatestSysVehicleLocationByVehicleId(vehicleId);
    }

    /**
     * 根据车牌号查询车辆最新位置信息
     *
     * @param licensePlate 车牌号
     * @return 车辆运动信息
     */
    @Override
    public SysVehicleLocation selectLatestSysVehicleLocationByLicensePlate(String licensePlate) {
        return sysVehicleLocationMapper.selectLatestSysVehicleLocationByLicensePlate(licensePlate);
    }

    /**
     * 获取车辆轨迹数据
     */
    @Override
    public VehicleTrajectoryVO getVehicleTrajectory(Long vehicleId, Date startTime, Date endTime,
            Boolean simplified, Integer maxPoints) {
        // 参数校验
        if (vehicleId == null || startTime == null || endTime == null) {
            throw new IllegalArgumentException("车辆ID、开始时间和结束时间不能为空");
        }

        if (startTime.after(endTime)) {
            throw new IllegalArgumentException("开始时间不能晚于结束时间");
        }

        // 查询轨迹数据
        List<SysVehicleLocation> locations = sysVehicleLocationMapper
                .selectVehicleTrajectory(vehicleId, startTime, endTime, simplified, maxPoints);

        if (CollectionUtils.isEmpty(locations)) {
            return createEmptyTrajectory(vehicleId, startTime, endTime);
        }

        // 获取车辆基础信息（从第一条记录中获取）
        SysVehicleLocation firstLocation = locations.get(0);

        // 转换轨迹点数据
        List<TrajectoryPoint> points = convertToTrajectoryPoints(locations);

        // 获取统计信息
        TrajectoryStatistics statistics = getTrajectoryStatistics(vehicleId, startTime, endTime);

        // 构建返回结果
        return VehicleTrajectoryVO.builder()
                .vehicleId(vehicleId)
                .licensePlate(firstLocation.getLicensePlate())
                .vehicleType(firstLocation.getVehicleType())
                .brand(firstLocation.getBrand())
                .owningUnit(firstLocation.getOwningUnit())
                .startTime(startTime)
                .endTime(endTime)
                .statistics(statistics)
                .points(points)
                .simplified(simplified)
                .dataQuality(calculateOverallDataQuality(locations))
                .build();
    }

    /**
     * 批量获取多车辆轨迹数据
     */
    @Override
    public List<VehicleTrajectoryVO> getBatchVehicleTrajectory(TrajectoryQueryRequest request) {
        // 参数校验
        if (request == null || CollectionUtils.isEmpty(request.getVehicleIds())
                || request.getStartTime() == null || request.getEndTime() == null) {
            throw new IllegalArgumentException("请求参数不能为空");
        }

        List<VehicleTrajectoryVO> result = new ArrayList<>();

        // 批量查询轨迹数据
        List<SysVehicleLocation> allLocations = sysVehicleLocationMapper
                .selectBatchVehicleTrajectory(request.getVehicleIds(), request.getStartTime(),
                        request.getEndTime(), request.getSimplified(), request.getMaxPoints());

        // 按车辆ID分组
        Map<Long, List<SysVehicleLocation>> locationsByVehicle = allLocations.stream()
                .collect(Collectors.groupingBy(SysVehicleLocation::getVehicleId));

        // 为每个车辆构建轨迹数据
        for (Long vehicleId : request.getVehicleIds()) {
            List<SysVehicleLocation> vehicleLocations = locationsByVehicle.get(vehicleId);

            if (CollectionUtils.isEmpty(vehicleLocations)) {
                result.add(createEmptyTrajectory(vehicleId, request.getStartTime(), request.getEndTime()));
                continue;
            }

            VehicleTrajectoryVO trajectory = buildTrajectoryFromLocations(vehicleId, vehicleLocations,
                    request.getStartTime(), request.getEndTime(), request.getSimplified(),
                    request.getIncludeStatistics());
            result.add(trajectory);
        }

        return result;
    }

    /**
     * 获取轨迹回放数据
     */
    @Override
    public List<VehicleLocationPlaybackVO> getTrajectoryPlaybackData(Long vehicleId, Date startTime,
            Date endTime, Integer intervalSeconds) {
        // 参数校验
        if (vehicleId == null || startTime == null || endTime == null || intervalSeconds == null) {
            throw new IllegalArgumentException("参数不能为空");
        }

        if (intervalSeconds <= 0) {
            throw new IllegalArgumentException("时间间隔必须大于0");
        }

        // 查询回放数据
        List<SysVehicleLocation> locations = sysVehicleLocationMapper
                .selectTrajectoryPlaybackData(vehicleId, startTime, endTime, intervalSeconds);

        if (CollectionUtils.isEmpty(locations)) {
            return new ArrayList<>();
        }

        // 转换为回放数据
        return convertToPlaybackData(locations, startTime, endTime);
    }

    /**
     * 获取车辆在指定区域内的轨迹
     */
    @Override
    public VehicleTrajectoryVO getVehicleTrajectoryInArea(Long vehicleId, Date startTime, Date endTime,
            String areaWkt) {
        // 参数校验
        if (vehicleId == null || startTime == null || endTime == null || !StringUtils.hasText(areaWkt)) {
            throw new IllegalArgumentException("参数不能为空");
        }

        // 查询区域内轨迹数据
        List<SysVehicleLocation> locations = sysVehicleLocationMapper
                .selectVehicleTrajectoryInArea(vehicleId, startTime, endTime, areaWkt);

        if (CollectionUtils.isEmpty(locations)) {
            return createEmptyTrajectory(vehicleId, startTime, endTime);
        }

        // 构建轨迹数据
        return buildTrajectoryFromLocations(vehicleId, locations, startTime, endTime, false, true);
    }

    /**
     * 获取轨迹统计信息
     */
    @Override
    public TrajectoryStatistics getTrajectoryStatistics(Long vehicleId, Date startTime, Date endTime) {
        // 参数校验
        if (vehicleId == null || startTime == null || endTime == null) {
            throw new IllegalArgumentException("参数不能为空");
        }

        // 查询统计信息
        TrajectoryStatistics statistics = sysVehicleLocationMapper
                .selectTrajectoryStatistics(vehicleId, startTime, endTime);

        if (statistics == null) {
            return createEmptyStatistics(startTime, endTime);
        }

        // 格式化时长
        if (statistics.getDurationSeconds() != null) {
            statistics.setDurationFormatted(formatDuration(statistics.getDurationSeconds()));
        }

        return statistics;
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 创建空轨迹对象
     */
    private VehicleTrajectoryVO createEmptyTrajectory(Long vehicleId, Date startTime, Date endTime) {
        return VehicleTrajectoryVO.builder()
                .vehicleId(vehicleId)
                .startTime(startTime)
                .endTime(endTime)
                .statistics(createEmptyStatistics(startTime, endTime))
                .points(new ArrayList<>())
                .simplified(false)
                .build();
    }

    /**
     * 创建空统计信息
     */
    private TrajectoryStatistics createEmptyStatistics(Date startTime, Date endTime) {
        return TrajectoryStatistics.builder()
                .pointCount(0)
                .firstPointTime(startTime)
                .lastPointTime(endTime)
                .averageSpeed(BigDecimal.ZERO)
                .maxSpeed(BigDecimal.ZERO)
                .minSpeed(BigDecimal.ZERO)
                .durationSeconds(0L)
                .durationFormatted("0分钟")
                .totalDistance(BigDecimal.ZERO)
                .stopCount(0)
                .totalStopDuration(0L)
                .maxAltitude(BigDecimal.ZERO)
                .minAltitude(BigDecimal.ZERO)
                .averageAltitude(BigDecimal.ZERO)
                .build();
    }

    /**
     * 转换为轨迹点列表
     */
    private List<TrajectoryPoint> convertToTrajectoryPoints(List<SysVehicleLocation> locations) {
        if (CollectionUtils.isEmpty(locations)) {
            return new ArrayList<>();
        }

        List<TrajectoryPoint> points = new ArrayList<>();
        SysVehicleLocation previousLocation = null;

        for (SysVehicleLocation location : locations) {
            TrajectoryPoint.TrajectoryPointBuilder pointBuilder = TrajectoryPoint.builder()
                    .longitude(location.getLongitude())
                    .latitude(location.getLatitude())
                    .altitude(location.getAltitude())
                    .speed(location.getSpeed())
                    .heading(location.getHeading())
                    .timestamp(location.getTimestamp())
                    .dataQuality(location.getDataQuality())
                    .location(location.getLocation())
                    .isStopPoint(isStopPoint(location));

            // 计算与前一点的距离和时间间隔
            if (previousLocation != null) {
                pointBuilder.distanceFromPrevious(calculateDistance(previousLocation, location));
                pointBuilder.timeIntervalFromPrevious(calculateTimeInterval(previousLocation, location));
            }

            points.add(pointBuilder.build());
            previousLocation = location;
        }

        return points;
    }

    /**
     * 转换为回放数据
     */
    private List<VehicleLocationPlaybackVO> convertToPlaybackData(List<SysVehicleLocation> locations,
            Date startTime, Date endTime) {
        if (CollectionUtils.isEmpty(locations)) {
            return new ArrayList<>();
        }

        List<VehicleLocationPlaybackVO> playbackData = new ArrayList<>();
        AtomicLong sequenceNumber = new AtomicLong(1);
        BigDecimal cumulativeDistance = BigDecimal.ZERO;
        long cumulativeTime = 0;
        long totalDuration = (endTime.getTime() - startTime.getTime()) / 1000; // 总时长(秒)

        SysVehicleLocation previousLocation = null;

        for (SysVehicleLocation location : locations) {
            // 计算累计距离和时间
            if (previousLocation != null) {
                BigDecimal distance = calculateDistance(previousLocation, location);
                cumulativeDistance = cumulativeDistance.add(distance);
                cumulativeTime += calculateTimeInterval(previousLocation, location);
            }

            // 计算进度百分比
            long currentTime = (location.getTimestamp().getTime() - startTime.getTime()) / 1000;
            BigDecimal progressPercentage = totalDuration > 0
                    ? BigDecimal.valueOf(currentTime * 100.0 / totalDuration).setScale(2, RoundingMode.HALF_UP)
                    : BigDecimal.ZERO;

            // 计算与上一点的时间间隔
            Long intervalMs = previousLocation != null
                    ? location.getTimestamp().getTime() - previousLocation.getTimestamp().getTime()
                    : 0L;

            VehicleLocationPlaybackVO playbackVO = VehicleLocationPlaybackVO.builder()
                    .vehicleId(location.getVehicleId())
                    .licensePlate(location.getLicensePlate())
                    .vehicleType(location.getVehicleType())
                    .sequenceNumber(sequenceNumber.getAndIncrement())
                    .longitude(location.getLongitude())
                    .latitude(location.getLatitude())
                    .altitude(location.getAltitude())
                    .speed(location.getSpeed())
                    .heading(location.getHeading())
                    .timestamp(location.getTimestamp())
                    .dataQuality(location.getDataQuality())
                    .intervalMs(intervalMs)
                    .cumulativeDistance(cumulativeDistance)
                    .cumulativeTime(cumulativeTime)
                    .progressPercentage(progressPercentage)
                    .isKeyFrame(isKeyFrame(location, previousLocation))
                    .keyFrameType(getKeyFrameType(location, previousLocation, sequenceNumber.get() == 2,
                            sequenceNumber.get() == locations.size() + 1))
                    .suggestedDelay(calculateSuggestedDelay(intervalMs))
                    .build();

            playbackData.add(playbackVO);
            previousLocation = location;
        }

        return playbackData;
    }

    /**
     * 从位置数据构建轨迹对象
     */
    private VehicleTrajectoryVO buildTrajectoryFromLocations(Long vehicleId, List<SysVehicleLocation> locations,
            Date startTime, Date endTime, Boolean simplified,
            Boolean includeStatistics) {
        if (CollectionUtils.isEmpty(locations)) {
            return createEmptyTrajectory(vehicleId, startTime, endTime);
        }

        SysVehicleLocation firstLocation = locations.get(0);
        List<TrajectoryPoint> points = convertToTrajectoryPoints(locations);

        TrajectoryStatistics statistics = null;
        if (includeStatistics != null && includeStatistics) {
            statistics = getTrajectoryStatistics(vehicleId, startTime, endTime);
        }

        return VehicleTrajectoryVO.builder()
                .vehicleId(vehicleId)
                .licensePlate(firstLocation.getLicensePlate())
                .vehicleType(firstLocation.getVehicleType())
                .brand(firstLocation.getBrand())
                .owningUnit(firstLocation.getOwningUnit())
                .startTime(startTime)
                .endTime(endTime)
                .statistics(statistics)
                .points(points)
                .simplified(simplified)
                .dataQuality(calculateOverallDataQuality(locations))
                .build();
    }

    /**
     * 计算两点间距离(米)
     */
    private BigDecimal calculateDistance(SysVehicleLocation from, SysVehicleLocation to) {
        if (from == null || to == null ||
                from.getLongitude() == null || from.getLatitude() == null ||
                to.getLongitude() == null || to.getLatitude() == null) {
            return BigDecimal.ZERO;
        }

        return GeoUtils.calculateDistanceAsBigDecimal(
                from.getLatitude().doubleValue(),
                from.getLongitude().doubleValue(),
                to.getLatitude().doubleValue(),
                to.getLongitude().doubleValue());
    }

    /**
     * 计算两点间时间间隔(秒)
     */
    private Long calculateTimeInterval(SysVehicleLocation from, SysVehicleLocation to) {
        if (from == null || to == null || from.getTimestamp() == null || to.getTimestamp() == null) {
            return 0L;
        }
        return (to.getTimestamp().getTime() - from.getTimestamp().getTime()) / 1000;
    }

    /**
     * 判断是否为停车点
     */
    private Boolean isStopPoint(SysVehicleLocation location) {
        if (location == null || location.getSpeed() == null) {
            return false;
        }
        return location.getSpeed().compareTo(BigDecimal.valueOf(2.0)) <= 0; // 速度小于等于2km/h认为是停车
    }

    /**
     * 判断是否为关键帧
     */
    private Boolean isKeyFrame(SysVehicleLocation current, SysVehicleLocation previous) {
        if (current == null) {
            return false;
        }
        if (previous == null) {
            return true; // 起点
        }

        // 速度变化较大
        if (current.getSpeed() != null && previous.getSpeed() != null) {
            BigDecimal speedDiff = current.getSpeed().subtract(previous.getSpeed()).abs();
            if (speedDiff.compareTo(BigDecimal.valueOf(10.0)) > 0) {
                return true;
            }
        }

        // 方向变化较大
        if (current.getHeading() != null && previous.getHeading() != null) {
            BigDecimal headingDiff = current.getHeading().subtract(previous.getHeading()).abs();
            if (headingDiff.compareTo(BigDecimal.valueOf(30.0)) > 0) {
                return true;
            }
        }

        return false;
    }

    /**
     * 获取关键帧类型
     */
    private String getKeyFrameType(SysVehicleLocation current, SysVehicleLocation previous,
            boolean isFirst, boolean isLast) {
        if (isFirst) {
            return "START";
        }
        if (isLast) {
            return "END";
        }
        if (isStopPoint(current)) {
            return "STOP";
        }
        if (isKeyFrame(current, previous)) {
            return "TURN";
        }
        return null;
    }

    /**
     * 计算建议延迟时间(毫秒)
     */
    private Long calculateSuggestedDelay(Long intervalMs) {
        if (intervalMs == null || intervalMs <= 0) {
            return 1000L; // 默认1秒
        }

        // 根据实际时间间隔调整回放速度
        if (intervalMs < 5000) {
            return intervalMs; // 小于5秒，按实际时间播放
        } else if (intervalMs < 30000) {
            return intervalMs / 2; // 5-30秒，2倍速播放
        } else {
            return Math.min(intervalMs / 5, 10000L); // 大于30秒，5倍速播放，最大10秒
        }
    }

    /**
     * 计算整体数据质量
     */
    private String calculateOverallDataQuality(List<SysVehicleLocation> locations) {
        if (CollectionUtils.isEmpty(locations)) {
            return "UNKNOWN";
        }

        Map<String, Long> qualityCount = locations.stream()
                .filter(loc -> StringUtils.hasText(loc.getDataQuality()))
                .collect(Collectors.groupingBy(SysVehicleLocation::getDataQuality, Collectors.counting()));

        if (qualityCount.isEmpty()) {
            return "UNKNOWN";
        }

        // 按质量等级排序，返回最高质量
        if (qualityCount.containsKey("HIGH")) {
            return "HIGH";
        } else if (qualityCount.containsKey("MEDIUM")) {
            return "MEDIUM";
        } else if (qualityCount.containsKey("LOW")) {
            return "LOW";
        } else {
            return "UNKNOWN";
        }
    }

    /**
     * 格式化时长
     */
    private String formatDuration(Long durationSeconds) {
        if (durationSeconds == null || durationSeconds <= 0) {
            return "0分钟";
        }

        long hours = durationSeconds / 3600;
        long minutes = (durationSeconds % 3600) / 60;
        long seconds = durationSeconds % 60;

        StringBuilder sb = new StringBuilder();
        if (hours > 0) {
            sb.append(hours).append("小时");
        }
        if (minutes > 0) {
            sb.append(minutes).append("分钟");
        }
        if (seconds > 0 && hours == 0) { // 只有在小于1小时时才显示秒
            sb.append(seconds).append("秒");
        }

        return sb.length() > 0 ? sb.toString() : "0分钟";
    }
}