package com.qaup.collision.rule.repository;

import com.qaup.collision.rule.model.entity.SpatialRule;
import com.qaup.collision.rule.model.enums.RuleCategory;
import com.qaup.collision.rule.model.enums.RuleStatus;
import com.qaup.collision.rule.model.enums.SpatialObjectType;

import org.locationtech.jts.geom.Point;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

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

/**
 * 空间规则数据访问接口
 * 提供空间规则的各种查询和操作方法
 * 
 * @author AI Assistant
 * @version 1.0
 * @since 2025-01-17
 */
@Repository
public interface SpatialRuleRepository extends JpaRepository<SpatialRule, String> {

    /**
     * 根据规则状态查询规则
     * @param status 规则状态
     * @return 指定状态的规则列表
     */
    List<SpatialRule> findByStatus(RuleStatus status);

    /**
     * 根据规则分类查询规则
     * @param category 规则分类
     * @return 指定分类的规则列表
     */
    List<SpatialRule> findByCategory(RuleCategory category);

    /**
     * 根据空间对象类型查询规则
     * @param spatialObjectType 空间对象类型
     * @return 指定空间对象类型的规则列表
     */
    List<SpatialRule> findBySpatialObjectType(SpatialObjectType spatialObjectType);

    /**
     * 根据空间对象ID查询规则
     * @param spatialObjectId 空间对象ID
     * @return 关联指定空间对象的规则列表
     */
    List<SpatialRule> findBySpatialObjectId(String spatialObjectId);

    /**
     * 根据空间对象类型和空间对象ID查询规则
     * @param spatialObjectType 空间对象类型
     * @param spatialObjectId 空间对象ID
     * @return 符合条件的规则列表
     */
    List<SpatialRule> findBySpatialObjectTypeAndSpatialObjectId(SpatialObjectType spatialObjectType, String spatialObjectId);

    /**
     * 根据区域ID查询规则
     * @param areaId 区域ID
     * @return 关联指定区域的规则列表
     */
    @Query("SELECT r FROM SpatialRule r WHERE r.spatialObjectType = 'AREA' AND r.spatialObjectId = :areaId")
    List<SpatialRule> findByAreaId(@Param("areaId") String areaId);

    /**
     * 根据道路ID查询规则
     * @param roadId 道路ID
     * @return 关联指定道路的规则列表
     */
    @Query("SELECT r FROM SpatialRule r WHERE r.spatialObjectType = 'ROAD' AND r.spatialObjectId = :roadId")
    List<SpatialRule> findByRoadId(@Param("roadId") String roadId);

    /**
     * 根据路口ID查询规则
     * @param intersectionId 路口ID
     * @return 关联指定路口的规则列表
     */
    @Query("SELECT r FROM SpatialRule r WHERE r.spatialObjectType = 'INTERSECTION' AND r.spatialObjectId = :intersectionId")
    List<SpatialRule> findByIntersectionId(@Param("intersectionId") String intersectionId);

    /**
     * 查询当前有效的规则（状态为ACTIVE且在有效时间范围内）
     * @param currentTime 当前时间
     * @return 当前有效的规则列表
     */
    @Query("SELECT r FROM SpatialRule r WHERE r.status = 'ACTIVE' " +
           "AND (r.effectiveStartTime IS NULL OR r.effectiveStartTime <= :currentTime) " +
           "AND (r.effectiveEndTime IS NULL OR r.effectiveEndTime >= :currentTime)")
    List<SpatialRule> findCurrentlyEffectiveRules(@Param("currentTime") LocalDateTime currentTime);

    /**
     * 根据规则分类和状态查询规则
     * @param category 规则分类
     * @param status 规则状态
     * @return 符合条件的规则列表
     */
    List<SpatialRule> findByCategoryAndStatus(RuleCategory category, RuleStatus status);

    /**
     * 根据空间对象类型和状态查询规则
     * @param spatialObjectType 空间对象类型
     * @param status 规则状态
     * @return 符合条件的规则列表
     */
    List<SpatialRule> findBySpatialObjectTypeAndStatus(SpatialObjectType spatialObjectType, RuleStatus status);

    /**
     * 查询按优先级排序的有效规则
     * @param status 规则状态
     * @return 按优先级排序的规则列表（优先级数值越小越靠前）
     */
    List<SpatialRule> findByStatusOrderByPriorityAsc(RuleStatus status);

    /**
     * 根据位置查询相关的空间规则（用于自定义几何形状的规则）
     * @param point 位置点
     * @return 包含该位置的自定义几何规则列表
     */
    @Query(value = "SELECT r.* FROM spatial_rules r " +
                   "WHERE r.spatial_object_type = 'CUSTOM_GEOMETRY' " +
                   "AND r.status = 'ACTIVE' " +
                   "AND ST_Contains(r.custom_geometry, :point)",
           nativeQuery = true)
    List<SpatialRule> findCustomGeometryRulesContainingPoint(@Param("point") Point point);

    /**
     * 根据区域查询所有相关的有效规则（包括直接关联区域和包含该区域的自定义几何）
     * @param areaId 区域ID
     * @param areaGeometry 区域几何形状
     * @return 与该区域相关的所有有效规则
     */
    @Query(value = "SELECT r.* FROM spatial_rules r " +
                   "WHERE r.status = 'ACTIVE' " +
                   "AND ((r.spatial_object_type = 'AREA' AND r.spatial_object_id = :areaId) " +
                   "OR (r.spatial_object_type = 'CUSTOM_GEOMETRY' AND ST_Intersects(r.custom_geometry, :areaGeometry)))",
           nativeQuery = true)
    List<SpatialRule> findRulesRelatedToArea(@Param("areaId") String areaId, 
                                            @Param("areaGeometry") Object areaGeometry);

    /**
     * 查询指定时间段内生效的规则
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 在指定时间段内生效的规则列表
     */
    @Query("SELECT r FROM SpatialRule r WHERE r.status = 'ACTIVE' " +
           "AND ((r.effectiveStartTime IS NULL OR r.effectiveStartTime <= :endTime) " +
           "AND (r.effectiveEndTime IS NULL OR r.effectiveEndTime >= :startTime))")
    List<SpatialRule> findRulesEffectiveInTimeRange(@Param("startTime") LocalDateTime startTime,
                                                    @Param("endTime") LocalDateTime endTime);

    /**
     * 查询包含指定每日时间段的规则
     * @param dailyStartTime 每日开始时间
     * @param dailyEndTime 每日结束时间
     * @return 包含指定每日时间段的规则列表
     */
    @Query("SELECT r FROM SpatialRule r WHERE r.status = 'ACTIVE' " +
           "AND ((r.dailyStartTime IS NULL OR r.dailyStartTime <= :dailyEndTime) " +
           "AND (r.dailyEndTime IS NULL OR r.dailyEndTime >= :dailyStartTime))")
    List<SpatialRule> findRulesEffectiveInDailyTimeRange(@Param("dailyStartTime") LocalTime dailyStartTime,
                                                         @Param("dailyEndTime") LocalTime dailyEndTime);

    /**
     * 根据星期模式查询规则
     * @param weekdayBit 星期位掩码（例如：周一=1, 周二=2, 周三=4...）
     * @return 在指定星期生效的规则列表
     */
    @Query(value = "SELECT * FROM spatial_rules r WHERE r.status = 'ACTIVE' " +
                   "AND (r.weekday_pattern IS NULL OR (r.weekday_pattern & :weekdayBit) > 0)",
           nativeQuery = true)
    List<SpatialRule> findRulesEffectiveOnWeekday(@Param("weekdayBit") Integer weekdayBit);

    /**
     * 查询特定规则分类的统计信息
     * @param category 规则分类
     * @return 各状态的规则数量统计
     */
    @Query("SELECT r.status, COUNT(r) FROM SpatialRule r WHERE r.category = :category GROUP BY r.status")
    List<Object[]> countByCategoryGroupByStatus(@Param("category") RuleCategory category);

    /**
     * 查询即将过期的规则（在指定时间内过期）
     * @param beforeTime 截止时间
     * @return 即将过期的规则列表
     */
    @Query("SELECT r FROM SpatialRule r WHERE r.status = 'ACTIVE' " +
           "AND r.effectiveEndTime IS NOT NULL " +
           "AND r.effectiveEndTime <= :beforeTime")
    List<SpatialRule> findRulesExpiringBefore(@Param("beforeTime") LocalDateTime beforeTime);

    /**
     * 根据创建者查询规则
     * @param createdBy 创建者
     * @return 指定创建者创建的规则列表
     */
    List<SpatialRule> findByCreatedBy(String createdBy);

    /**
     * 根据优先级范围查询规则
     * @param minPriority 最小优先级
     * @param maxPriority 最大优先级
     * @param status 规则状态
     * @return 在指定优先级范围内的规则列表
     */
    @Query("SELECT r FROM SpatialRule r WHERE r.status = :status " +
           "AND r.priority >= :minPriority AND r.priority <= :maxPriority " +
           "ORDER BY r.priority ASC")
    List<SpatialRule> findByPriorityRangeAndStatus(@Param("minPriority") Integer minPriority,
                                                   @Param("maxPriority") Integer maxPriority,
                                                   @Param("status") RuleStatus status);

    /**
     * 检查规则ID是否已存在
     * @param ruleId 规则ID
     * @return 如果规则ID已存在返回true
     */
    boolean existsByRuleId(String ruleId);

    /**
     * 根据规则名称查询规则（支持模糊查询）
     * @param ruleName 规则名称关键字
     * @return 名称包含关键字的规则列表
     */
    @Query("SELECT r FROM SpatialRule r WHERE r.name LIKE :ruleName")
    List<SpatialRule> findByNameContaining(@Param("ruleName") String ruleName);

    /**
     * 根据空间对象ID和规则分类查询规则
     * @param spatialObjectId 空间对象ID
     * @param category 规则分类
     * @return 符合条件的规则列表
     */
    List<SpatialRule> findBySpatialObjectIdAndCategory(String spatialObjectId, RuleCategory category);

    /**
     * 软删除规则（更新状态为DELETED）
     * @param ruleId 规则ID
     * @param updatedBy 更新者
     * @param updatedAt 更新时间
     * @return 更新的记录数
     */
    @Query("UPDATE SpatialRule r SET r.status = 'DELETED', r.updatedBy = :updatedBy, r.updatedAt = :updatedAt " +
           "WHERE r.ruleId = :ruleId AND r.status != 'DELETED'")
    int softDeleteRule(@Param("ruleId") String ruleId, 
                       @Param("updatedBy") String updatedBy, 
                       @Param("updatedAt") LocalDateTime updatedAt);

    /**
     * 批量更新规则状态
     * @param ruleIds 规则ID列表
     * @param newStatus 新状态
     * @param updatedBy 更新者
     * @param updatedAt 更新时间
     * @return 更新的记录数
     */
    @Query("UPDATE SpatialRule r SET r.status = :newStatus, r.updatedBy = :updatedBy, r.updatedAt = :updatedAt " +
           "WHERE r.ruleId IN :ruleIds")
    int batchUpdateStatus(@Param("ruleIds") List<String> ruleIds,
                          @Param("newStatus") RuleStatus newStatus,
                          @Param("updatedBy") String updatedBy,
                          @Param("updatedAt") LocalDateTime updatedAt);
} 