package com.qaup.collision.rule.service;

import com.qaup.collision.common.model.MovingObject.MovingObjectType;
import com.qaup.collision.common.model.spatial.VehicleLocation;
import com.qaup.collision.rule.model.entity.SpatialRule;
import com.qaup.collision.rule.model.enums.RuleCategory;

import org.locationtech.jts.geom.Point;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 基于位置的适用规则查询服务接口
 * 提供根据车辆位置、类型、时间等条件查询适用规则的功能
 * 
 * @author AI Assistant
 * @version 1.0
 * @since 2025-01-17
 */
public interface LocationRuleQueryService {

    /**
     * 查询指定位置的所有适用规则
     * @param location 位置点
     * @param vehicleType 车辆类型
     * @param timestamp 查询时间
     * @return 适用的规则列表，按优先级排序
     */
    List<SpatialRule> findApplicableRules(Point location, MovingObjectType vehicleType, LocalDateTime timestamp);

    /**
     * 查询指定位置的特定分类规则
     * @param location 位置点
     * @param vehicleType 车辆类型
     * @param ruleCategory 规则分类
     * @param timestamp 查询时间
     * @return 适用的规则列表
     */
    List<SpatialRule> findApplicableRulesByCategory(Point location, MovingObjectType vehicleType, 
                                                    RuleCategory ruleCategory, LocalDateTime timestamp);

    /**
     * 查询车辆位置的所有适用规则
     * @param vehicleLocation 车辆位置信息
     * @return 适用的规则列表
     */
    List<SpatialRule> findApplicableRulesForVehicle(VehicleLocation vehicleLocation);

    /**
     * 查询指定位置范围内的规则
     * @param centerLocation 中心位置
     * @param radiusMeters 查询半径（米）
     * @param vehicleType 车辆类型
     * @param timestamp 查询时间
     * @return 范围内的规则列表
     */
    List<SpatialRule> findRulesInRadius(Point centerLocation, double radiusMeters, 
                                        MovingObjectType vehicleType, LocalDateTime timestamp);

    /**
     * 查询车辆轨迹上的所有规则
     * @param trajectory 轨迹点列表
     * @param vehicleType 车辆类型
     * @param timestamp 查询时间
     * @return 轨迹上的规则列表（去重）
     */
    List<SpatialRule> findRulesAlongTrajectory(List<Point> trajectory, MovingObjectType vehicleType, 
                                               LocalDateTime timestamp);

    /**
     * 检查位置是否在规则覆盖范围内
     * @param location 位置点
     * @param rule 规则
     * @return 如果在覆盖范围内返回true
     */
    boolean isLocationInRuleScope(Point location, SpatialRule rule);

    /**
     * 检查规则是否对指定车辆类型适用
     * @param rule 规则
     * @param vehicleType 车辆类型
     * @return 如果适用返回true
     */
    boolean isRuleApplicableToVehicleType(SpatialRule rule, MovingObjectType vehicleType);

    /**
     * 检查规则在指定时间是否有效
     * @param rule 规则
     * @param timestamp 检查时间
     * @return 如果有效返回true
     */
    boolean isRuleEffectiveAtTime(SpatialRule rule, LocalDateTime timestamp);

    /**
     * 获取位置的规则覆盖统计
     * @param location 位置点
     * @param vehicleType 车辆类型
     * @param timestamp 查询时间
     * @return 规则覆盖统计信息
     */
    RuleCoverageStats getRuleCoverageStats(Point location, MovingObjectType vehicleType, LocalDateTime timestamp);

    /**
     * 批量查询多个位置的适用规则
     * @param locations 位置列表
     * @param vehicleType 车辆类型
     * @param timestamp 查询时间
     * @return 位置到规则列表的映射
     */
    Map<Point, List<SpatialRule>> findApplicableRulesForLocations(List<Point> locations, 
                                                                  MovingObjectType vehicleType, 
                                                                  LocalDateTime timestamp);

    /**
     * 查询最高优先级的适用规则
     * @param location 位置点
     * @param vehicleType 车辆类型
     * @param ruleCategory 规则分类
     * @param timestamp 查询时间
     * @return 最高优先级的规则，如果没有适用规则返回null
     */
    SpatialRule findHighestPriorityRule(Point location, MovingObjectType vehicleType, 
                                        RuleCategory ruleCategory, LocalDateTime timestamp);

    /**
     * 预测车辆移动路径上的规则
     * @param currentLocation 当前位置
     * @param heading 航向角（度）
     * @param speed 速度（米/秒）
     * @param predictionTimeSeconds 预测时间（秒）
     * @param vehicleType 车辆类型
     * @return 预测路径上的规则列表
     */
    List<SpatialRule> predictRulesOnPath(Point currentLocation, double heading, double speed, 
                                         int predictionTimeSeconds, MovingObjectType vehicleType);

    /**
     * 查询规则的空间边界
     * @param rule 规则
     * @return 规则的空间边界几何形状
     */
    org.locationtech.jts.geom.Geometry getRuleBoundary(SpatialRule rule);

    /**
     * 计算位置到规则边界的距离
     * @param location 位置点
     * @param rule 规则
     * @return 距离（米），如果位置在规则内部返回0
     */
    double calculateDistanceToRule(Point location, SpatialRule rule);

    /**
     * 查询位置附近即将生效的规则
     * @param location 位置点
     * @param vehicleType 车辆类型
     * @param lookAheadMinutes 前瞻时间（分钟）
     * @return 即将生效的规则列表
     */
    List<SpatialRule> findUpcomingRules(Point location, MovingObjectType vehicleType, int lookAheadMinutes);

    /**
     * 检查车辆类型是否有权限访问指定位置
     * @param location 位置点
     * @param vehicleType 车辆类型
     * @param timestamp 时间戳
     * @return 如果有权限返回true
     */
    boolean hasAccessPermission(Point location, MovingObjectType vehicleType, LocalDateTime timestamp);

    /**
     * 获取车辆类型被禁止访问的规则列表
     * @param location 位置点
     * @param vehicleType 车辆类型
     * @param timestamp 时间戳
     * @return 被禁止的规则列表
     */
    List<SpatialRule> getRestrictedRules(Point location, MovingObjectType vehicleType, LocalDateTime timestamp);

    /**
     * 获取车辆类型允许访问的规则列表
     * @param location 位置点
     * @param vehicleType 车辆类型
     * @param timestamp 时间戳
     * @return 允许的规则列表
     */
    List<SpatialRule> getAllowedRules(Point location, MovingObjectType vehicleType, LocalDateTime timestamp);

    /**
     * 规则覆盖统计信息
     */
    class RuleCoverageStats {
        private int totalRules;
        private int applicableRules;
        private Map<RuleCategory, Integer> rulesByCategory;
        private int activeRules;
        private int inactiveRules;
        private double coveragePercentage;

        // 构造函数
        public RuleCoverageStats() {}

        public RuleCoverageStats(int totalRules, int applicableRules, Map<RuleCategory, Integer> rulesByCategory,
                                int activeRules, int inactiveRules) {
            this.totalRules = totalRules;
            this.applicableRules = applicableRules;
            this.rulesByCategory = rulesByCategory;
            this.activeRules = activeRules;
            this.inactiveRules = inactiveRules;
            this.coveragePercentage = totalRules > 0 ? (double) applicableRules / totalRules * 100 : 0;
        }

        // Getters and Setters
        public int getTotalRules() { return totalRules; }
        public void setTotalRules(int totalRules) { this.totalRules = totalRules; }

        public int getApplicableRules() { return applicableRules; }
        public void setApplicableRules(int applicableRules) { this.applicableRules = applicableRules; }

        public Map<RuleCategory, Integer> getRulesByCategory() { return rulesByCategory; }
        public void setRulesByCategory(Map<RuleCategory, Integer> rulesByCategory) { this.rulesByCategory = rulesByCategory; }

        public int getActiveRules() { return activeRules; }
        public void setActiveRules(int activeRules) { this.activeRules = activeRules; }

        public int getInactiveRules() { return inactiveRules; }
        public void setInactiveRules(int inactiveRules) { this.inactiveRules = inactiveRules; }

        public double getCoveragePercentage() { return coveragePercentage; }
        public void setCoveragePercentage(double coveragePercentage) { this.coveragePercentage = coveragePercentage; }

        @Override
        public String toString() {
            return String.format("RuleCoverageStats{totalRules=%d, applicableRules=%d, coveragePercentage=%.2f%%}", 
                               totalRules, applicableRules, coveragePercentage);
        }
    }
} 