package com.qaup.collision.common.service;

import com.qaup.collision.common.model.spatial.VehicleLocation;
import com.qaup.collision.common.model.base.CacheConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 车辆位置缓存服务类
 * 基于Redis实现车辆位置数据的高性能缓存
 * 
 * 主要功能：
 * 1. 车辆最新位置缓存
 * 2. 车辆轨迹数据缓存
 * 3. 批量操作支持
 * 4. 缓存穿透保护
 * 5. 缓存预热
 */
@Slf4j
@Service
public class VehicleLocationCacheService {

    private final RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    public VehicleLocationCacheService(
            @Qualifier("redisTemplate") RedisTemplate<Object, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 缓存车辆最新位置
     * 
     * @param vehicleLocation 车辆位置信息
     */
    public void cacheLatestLocation(VehicleLocation vehicleLocation) {
        try {
            // 将Long类型的vehicleId转换为String类型用于缓存key
            String key = CacheConstants.buildVehicleLatestKey(vehicleLocation.getVehicleId());
            redisTemplate.opsForValue()
                .set(key, vehicleLocation, CacheConstants.VEHICLE_LATEST_EXPIRE, TimeUnit.SECONDS);
            
            log.debug("缓存车辆最新位置: vehicleId={}, timestamp={}", 
                     vehicleLocation.getVehicleId(), vehicleLocation.getTimestamp());
        } catch (Exception e) {
            log.warn("缓存车辆最新位置失败: vehicleId={}", vehicleLocation.getVehicleId(), e);
        }
    }

    /**
     * 获取车辆最新位置
     * 
     * @param vehicleId 车辆ID
     * @return 车辆最新位置，不存在则返回null
     */
    public VehicleLocation getLatestLocation(Long vehicleId) {
        try {
            String key = CacheConstants.buildVehicleLatestKey(vehicleId);
            VehicleLocation location = (VehicleLocation) redisTemplate.opsForValue().get(key);
            
            log.debug("获取车辆最新位置缓存: vehicleId={}, found={}", vehicleId, location != null);
            return location;
        } catch (Exception e) {
            log.warn("获取车辆最新位置缓存失败: vehicleId={}", vehicleId, e);
            return null;
        }
    }

    /**
     * 批量缓存车辆最新位置
     * 
     * @param vehicleLocations 车辆位置列表
     */
    public void batchCacheLatestLocations(List<VehicleLocation> vehicleLocations) {
        if (vehicleLocations == null || vehicleLocations.isEmpty()) {
            return;
        }

        try {
            Map<String, VehicleLocation> cacheMap = new HashMap<>();
            for (VehicleLocation location : vehicleLocations) {
                // 将Long类型的vehicleId转换为String类型用于缓存key
                String key = CacheConstants.buildVehicleLatestKey(location.getVehicleId());
                cacheMap.put(key, location);
            }

            redisTemplate.opsForValue().multiSet(cacheMap);
            
            // 批量设置过期时间
            for (String key : cacheMap.keySet()) {
                redisTemplate.expire(key, CacheConstants.VEHICLE_LATEST_EXPIRE, TimeUnit.SECONDS);
            }

            log.debug("批量缓存车辆最新位置: 数量={}", vehicleLocations.size());
        } catch (Exception e) {
            log.warn("批量缓存车辆最新位置失败: 数量={}", vehicleLocations.size(), e);
        }
    }

    /**
     * 批量获取车辆最新位置
     * 
     * @param vehicleIds 车辆ID列表
     * @return 车辆位置映射
     */
    public Map<String, VehicleLocation> batchGetLatestLocations(List<Long> vehicleIds) {
        if (vehicleIds == null || vehicleIds.isEmpty()) {
            return Collections.emptyMap();
        }

        try {
            List<Object> keys = vehicleIds.stream()
                .map(CacheConstants::buildVehicleLatestKey)
                .map(key -> (Object) key)
                .collect(Collectors.toList());

            List<Object> locations = redisTemplate.opsForValue().multiGet(keys);
            if (locations == null) {
                return Collections.emptyMap();
            }

            Map<String, VehicleLocation> resultMap = new HashMap<>();
            for (int i = 0; i < vehicleIds.size(); i++) {
                Object locationObj = locations.get(i);
                if (locationObj != null && locationObj instanceof VehicleLocation) {
                    VehicleLocation location = (VehicleLocation) locationObj;
                    resultMap.put(String.valueOf(vehicleIds.get(i)), location);
                }
            }

            log.debug("批量获取车辆最新位置缓存: 请求数量={}, 命中数量={}", 
                     vehicleIds.size(), resultMap.size());
            return resultMap;
        } catch (Exception e) {
            log.warn("批量获取车辆最新位置缓存失败: 数量={}", vehicleIds.size(), e);
            return Collections.emptyMap();
        }
    }

    /**
     * 缓存车辆轨迹数据
     * 
     * @param vehicleId 车辆ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param trajectory 轨迹数据
     */
    public void cacheTrajectory(Long vehicleId, LocalDateTime startTime, LocalDateTime endTime, 
                               List<VehicleLocation> trajectory) {
        try {
            long startTimestamp = startTime.toEpochSecond(ZoneOffset.UTC);
            long endTimestamp = endTime.toEpochSecond(ZoneOffset.UTC);
            String key = CacheConstants.buildVehicleTrajectoryKey(vehicleId, startTimestamp, endTimestamp);
            
            redisTemplate.opsForValue()
                .set(key, trajectory, CacheConstants.VEHICLE_TRAJECTORY_EXPIRE, TimeUnit.SECONDS);
            
            log.debug("缓存车辆轨迹: vehicleId={}, 轨迹点数={}, 时间范围=[{}, {}]", 
                     vehicleId, trajectory.size(), startTime, endTime);
        } catch (Exception e) {
            log.warn("缓存车辆轨迹失败: vehicleId={}", vehicleId, e);
        }
    }

    /**
     * 获取车辆轨迹数据
     * 
     * @param vehicleId 车辆ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 轨迹数据，不存在则返回null
     */
    @SuppressWarnings("unchecked")
    public List<VehicleLocation> getTrajectory(Long vehicleId, LocalDateTime startTime, LocalDateTime endTime) {
        try {
            long startTimestamp = startTime.toEpochSecond(ZoneOffset.UTC);
            long endTimestamp = endTime.toEpochSecond(ZoneOffset.UTC);
            String key = CacheConstants.buildVehicleTrajectoryKey(vehicleId, startTimestamp, endTimestamp);
            
            Object result = redisTemplate.opsForValue().get(key);
            if (result instanceof List) {
                List<VehicleLocation> trajectory = (List<VehicleLocation>) result;
                log.debug("获取车辆轨迹缓存: vehicleId={}, 轨迹点数={}", vehicleId, trajectory.size());
                return trajectory;
            }
            
            log.debug("车辆轨迹缓存未命中: vehicleId={}", vehicleId);
            return null;
        } catch (Exception e) {
            log.warn("获取车辆轨迹缓存失败: vehicleId={}", vehicleId, e);
            return null;
        }
    }

    /**
     * 删除车辆相关的所有缓存
     * 
     * @param vehicleId 车辆ID
     */
    public void evictVehicleCache(Long vehicleId) {
        try {
            // 删除最新位置缓存
            String latestKey = CacheConstants.buildVehicleLatestKey(vehicleId);
            redisTemplate.delete(latestKey);
            
            // 删除轨迹缓存（使用模式匹配）
            String trajectoryPattern = CacheConstants.VEHICLE_TRAJECTORY_PREFIX + vehicleId + ":*";
            Set<Object> trajectoryKeys = (Set<Object>) redisTemplate.keys(trajectoryPattern);
            if (trajectoryKeys != null && !trajectoryKeys.isEmpty()) {
                redisTemplate.delete(trajectoryKeys);
            }
            
            log.debug("清除车辆缓存: vehicleId={}, 清除轨迹缓存数量={}", 
                     vehicleId, trajectoryKeys != null ? trajectoryKeys.size() : 0);
        } catch (Exception e) {
            log.warn("清除车辆缓存失败: vehicleId={}", vehicleId, e);
        }
    }

    /**
     * 检查车辆最新位置缓存是否存在
     * 
     * @param vehicleId 车辆ID
     * @return 是否存在
     */
    public boolean hasLatestLocationCache(Long vehicleId) {
        try {
            String key = CacheConstants.buildVehicleLatestKey(vehicleId);
            Boolean exists = redisTemplate.hasKey(key);
            return exists != null && exists;
        } catch (Exception e) {
            log.warn("检查车辆最新位置缓存失败: vehicleId={}", vehicleId, e);
            return false;
        }
    }

    /**
     * 获取缓存中的活跃车辆列表
     * 
     * @return 活跃车辆ID列表
     */
    public List<Long> getActiveVehicleIds() {
        try {
            String pattern = CacheConstants.VEHICLE_LATEST_PREFIX + "*";
            Set<Object> keys = (Set<Object>) redisTemplate.keys(pattern);
            
            if (keys == null || keys.isEmpty()) {
                return Collections.emptyList();
            }
            
            List<Long> vehicleIds = keys.stream()
                .map(key -> Long.parseLong(key.toString().substring(CacheConstants.VEHICLE_LATEST_PREFIX.length())))
                .collect(Collectors.toList());
            
            log.debug("获取活跃车辆列表: 数量={}", vehicleIds.size());
            return vehicleIds;
        } catch (Exception e) {
            log.warn("获取活跃车辆列表失败", e);
            return Collections.emptyList();
        }
    }

    /**
     * 清理过期的车辆位置缓存
     * 
     * @param beforeTime 清理此时间之前的缓存
     */
    public void cleanupExpiredCache(LocalDateTime beforeTime) {
        try {
            List<Long> activeVehicleIds = getActiveVehicleIds();
            int cleanedCount = 0;
            
            for (Long vehicleId : activeVehicleIds) {
                VehicleLocation location = getLatestLocation(vehicleId);
                if (location != null && location.getTimestamp().isBefore(beforeTime)) {
                    evictVehicleCache(vehicleId);
                    cleanedCount++;
                }
            }
            
            log.info("清理过期车辆位置缓存: 清理数量={}, 基准时间={}", cleanedCount, beforeTime);
        } catch (Exception e) {
            log.warn("清理过期车辆位置缓存失败", e);
        }
    }

    /**
     * 获取缓存统计信息
     * 
     * @return 缓存统计信息
     */
    public Map<String, Object> getCacheStatistics() {
        try {
            Map<String, Object> stats = new HashMap<>();
            
            // 活跃车辆数量
            List<Long> activeVehicles = getActiveVehicleIds();
            stats.put("activeVehicleCount", activeVehicles.size());
            
            // 轨迹缓存数量
            String trajectoryPattern = CacheConstants.VEHICLE_TRAJECTORY_PREFIX + "*";
            Set<Object> trajectoryKeys = (Set<Object>) redisTemplate.keys(trajectoryPattern);
            stats.put("trajectoryCacheCount", trajectoryKeys != null ? trajectoryKeys.size() : 0);
            
            // 缓存命中率（需要额外的计数器来实现）
            stats.put("cacheHitRate", "N/A");
            
            return stats;
        } catch (Exception e) {
            log.warn("获取缓存统计信息失败", e);
            return Collections.emptyMap();
        }
    }
} 