package com.qaup.collision.dataprocessing.service;

import com.qaup.common.utils.GeoUtils;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Value;

@Service
public class SpeedCalculationService {
   // 滑动窗口大小（秒）
   private static final int TAKEOFF_WINDOW_SIZE = 10;
   private static final int LANDING_WINDOW_SIZE = 5;

   // 加速度范围（米/秒²）
   private static final double MIN_TAKEOFF_ACCELERATION = 0.5;
   private static final double MAX_TAKEOFF_ACCELERATION = 2.5;
   private static final double MIN_LANDING_ACCELERATION = -2.0;
   private static final double MAX_LANDING_ACCELERATION = 0.0;

   // 异常值检测阈值
   private static final double MAX_POSITION_JUMP = 100.0; // 米
   private static final double MAX_TIME_JUMP = 5000.0;    // 毫秒

   
   /**
    * 实时速度计算相关 - 历史位置信息缓存
    * key: objectId (车辆ID或航班号)
    * value: 历史位置信息
    */
   private final Map<String, HistoricalPosition> positionHistory = new ConcurrentHashMap<>();
   
   /**
    * 检测间隔配置，用于确定速度计算的时间间隔
    * 速度计算应该基于输出频率而非采集频率
    */
   @Value("${data.collector.detection.interval:1000}")
   private long detectionInterval;

   
   // ==================== 实时速度计算功能 ====================
   
   /**
    * 基于位置变化计算实时速度（用于WebSocket推送）
    * @param objectId 对象ID
    * @param latitude 当前纬度
    * @param longitude 当前经度
    * @param timestamp 当前时间戳（毫秒）
    * @return 计算出的速度（公里/小时），如果无法计算则返回null
    */
   public Double calculateRealtimeSpeed(String objectId, double latitude, double longitude, long timestamp) {
       HistoricalPosition lastPosition = positionHistory.get(objectId);
       
       // 如果没有历史位置，保存当前位置并返回null
       if (lastPosition == null) {
           positionHistory.put(objectId, new HistoricalPosition(latitude, longitude, timestamp));
           return null;
       }
       
       // 计算时间差（秒）
       double timeDelta = (timestamp - lastPosition.timestamp) / 1000.0;
       
       // 速度计算应该基于输出频率（WebSocket推送间隔），而不是采集频率
       // 只有时间差达到输出间隔时才计算新速度
       double pushIntervalSeconds = detectionInterval / 1000.0;
       if (timeDelta < pushIntervalSeconds) {
           return lastPosition.lastCalculatedSpeed;
       }
       
       // 计算距离差（米）
       double distance = calculateGeographicDistance(lastPosition.latitude, lastPosition.longitude, latitude, longitude);
       
       // 计算速度（米/秒），然后转换为公里/小时
       double speedMps = distance / timeDelta;
       double speedKph = speedMps * 3.6; // 转换为公里/小时
       
       // 计算方向（度）
       double direction = calculateDirection(lastPosition.latitude, lastPosition.longitude, latitude, longitude);
       
       // 保留2位小数精度
       double roundedSpeed = Math.round(speedKph * 100.0) / 100.0;
       double roundedDirection = Math.round(direction * 100.0) / 100.0;
       
       // 更新历史位置
       HistoricalPosition newPosition = new HistoricalPosition(latitude, longitude, timestamp);
       newPosition.lastCalculatedSpeed = roundedSpeed;
       newPosition.lastCalculatedDirection = roundedDirection;
       positionHistory.put(objectId, newPosition);
       
       return roundedSpeed;
   }
   
   /**
    * 基于位置变化计算实时方向（用于WebSocket推送）
    * @param objectId 对象ID
    * @param latitude 当前纬度
    * @param longitude 当前经度
    * @param timestamp 当前时间戳（毫秒）
    * @return 计算出的方向（度，0-360度，正北为0度），如果无法计算则返回null
    */
   public Double calculateRealtimeDirection(String objectId, double latitude, double longitude, long timestamp) {
       HistoricalPosition lastPosition = positionHistory.get(objectId);
       
       // 如果没有历史位置，保存当前位置并返回null
       if (lastPosition == null) {
           positionHistory.put(objectId, new HistoricalPosition(latitude, longitude, timestamp));
           return null;
       }
       
       // 计算时间差（秒）
       double timeDelta = (timestamp - lastPosition.timestamp) / 1000.0;
       
       // 只有时间差达到输出间隔时才计算新方向
       double pushIntervalSeconds = detectionInterval / 1000.0;
       if (timeDelta < pushIntervalSeconds) {
           return lastPosition.lastCalculatedDirection;
       }
       
       // 计算方向（度）
       double direction = calculateDirection(lastPosition.latitude, lastPosition.longitude, latitude, longitude);
       
       // 如果距离太小（小于1米），保持上次的方向
       double distance = calculateGeographicDistance(lastPosition.latitude, lastPosition.longitude, latitude, longitude);
       if (distance < 1.0 && lastPosition.lastCalculatedDirection != null) {
           return lastPosition.lastCalculatedDirection;
       }
       
       // 保留2位小数精度
       double roundedDirection = Math.round(direction * 100.0) / 100.0;
       
       // 如果速度没有同时计算，只更新方向
       if (lastPosition.lastCalculatedSpeed == null || 
           Math.abs(timestamp - lastPosition.timestamp) >= detectionInterval) {
           // 计算速度（米/秒），然后转换为公里/小时
           double speedMps = distance / timeDelta;
           double speedKph = speedMps * 3.6; // 转换为公里/小时
           double roundedSpeed = Math.round(speedKph * 100.0) / 100.0;
           
           // 更新历史位置
           HistoricalPosition newPosition = new HistoricalPosition(latitude, longitude, timestamp);
           newPosition.lastCalculatedSpeed = roundedSpeed;
           newPosition.lastCalculatedDirection = roundedDirection;
           positionHistory.put(objectId, newPosition);
       }
       
       return roundedDirection;
   }

   /**
    * 获取对象的当前速度（不更新历史记录）
    * @param objectId 对象ID
    * @return 最后计算的速度（公里/小时），如果没有则返回null
    */
   public Double getCurrentSpeed(String objectId) {
       HistoricalPosition position = positionHistory.get(objectId);
       return position != null ? position.lastCalculatedSpeed : null;
   }
   
   /**
    * 获取对象的当前方向（不更新历史记录）
    * @param objectId 对象ID
    * @return 最后计算的方向（度，0-360度，正北为0度），如果没有则返回null
    */
   public Double getCurrentDirection(String objectId) {
       HistoricalPosition position = positionHistory.get(objectId);
       return position != null ? position.lastCalculatedDirection : null;
   }
   
   /**
    * 清除对象的历史位置信息
    * @param objectId 对象ID
    */
   public void clearHistory(String objectId) {
       positionHistory.remove(objectId);
   }
   
   /**
    * 清除所有历史位置信息
    */
   public void clearAllHistory() {
       positionHistory.clear();
   }
   
   /**
    * 使用Haversine公式计算两点间的地理距离
    * @param lat1 第一个点的纬度
    * @param lon1 第一个点的经度
    * @param lat2 第二个点的纬度
    * @param lon2 第二个点的经度
    * @return 距离（米）
    */
   private double calculateGeographicDistance(double lat1, double lon1, double lat2, double lon2) {
       return GeoUtils.calculateDistance(lat1, lon1, lat2, lon2);
   }
   
   /**
    * 计算两点间的方向角（方位角）
    * @param lat1 起点纬度
    * @param lon1 起点经度
    * @param lat2 终点纬度
    * @param lon2 终点经度
    * @return 方向角（度，0-360度，正北为0度，顺时针）
    */
   private double calculateDirection(double lat1, double lon1, double lat2, double lon2) {
       double lat1Rad = Math.toRadians(lat1);
       double lat2Rad = Math.toRadians(lat2);
       double deltaLonRad = Math.toRadians(lon2 - lon1);
       
       double y = Math.sin(deltaLonRad) * Math.cos(lat2Rad);
       double x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - 
                  Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(deltaLonRad);
       
       double bearingRad = Math.atan2(y, x);
       double bearingDeg = Math.toDegrees(bearingRad);
       
       // 将角度标准化到0-360度范围
       return (bearingDeg + 360) % 360;
   }
   
   /**
    * 历史位置信息类
    */
   private static class HistoricalPosition {
       final double latitude;
       final double longitude;
       final long timestamp;
       Double lastCalculatedSpeed;
       Double lastCalculatedDirection; // 添加方向字段
       
       HistoricalPosition(double latitude, double longitude, long timestamp) {
           this.latitude = latitude;
           this.longitude = longitude;
           this.timestamp = timestamp;
       }
   }
}
