package com.qaup.collision.geofence.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qaup.collision.common.model.MovingObject;
import com.qaup.collision.common.model.MovingObject.MovingObjectType;
import com.qaup.collision.common.model.spatial.AirportArea;
import com.qaup.collision.common.service.AirportAreaService;
import com.qaup.collision.geofence.model.dto.GeofenceAccessCheckResult;
import com.qaup.collision.geofence.model.dto.UnmannedVehicleGeofenceRuleConfig;
import com.qaup.collision.rule.model.entity.SpatialRule;
import com.qaup.collision.rule.model.enums.RuleAlertLevel;
import com.qaup.collision.rule.model.enums.RuleCategory;
import com.qaup.collision.rule.service.SpatialRuleService;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Point;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import com.qaup.collision.websocket.event.GeofenceAlertWebSocketEvent;
import com.qaup.collision.websocket.message.GeofenceAlertPayload;

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

/**
 * 无人车电子围栏检测服务
 * 专门负责无人车的区域准入检测
 * 
 * @author qaup-collision
 * @date 2025-01-15
 */
@Slf4j
@Service
public class UnmannedVehicleGeofenceService {
    
    @Autowired
    private AirportAreaService airportAreaService;
    
    @Autowired
    private SpatialRuleService spatialRuleService;
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    /**
     * 检测无人车是否可以进入指定区域
     * 
     * @param vehicle 移动对象（必须是无人车）
     * @param areaCode 区域编码
     * @return 检测结果
     */
    public GeofenceAccessCheckResult checkAreaAccess(MovingObject vehicle, String areaCode) {
        // 前置检查：必须是无人车
        if (vehicle.getObjectType() != MovingObjectType.UNMANNED_VEHICLE) {
            log.debug("跳过非无人车的围栏检测: {} (类型: {})", vehicle.getObjectId(), vehicle.getObjectType());
            return GeofenceAccessCheckResult.skipped(vehicle.getObjectId());
        }
        
        try {
            log.debug("开始电子围栏检测: 无人车={}, 区域={}", vehicle.getObjectId(), areaCode);
            
            // 1. 获取区域信息
            Optional<AirportArea> areaOpt = airportAreaService.findByAreaCode(areaCode);
            if (areaOpt.isEmpty()) {
                log.warn("未找到区域: {}", areaCode);
                return GeofenceAccessCheckResult.denied(areaCode, vehicle.getObjectId(), "区域不存在");
            }
            
            AirportArea area = areaOpt.get();
            
            // 2. 检查区域是否启用
            if (!Boolean.TRUE.equals(area.getEnabled())) {
                log.debug("区域已禁用: {}", areaCode);
                return GeofenceAccessCheckResult.denied(areaCode, vehicle.getObjectId(), "区域已禁用");
            }
            
            // 3. 查询适用的规则
            List<SpatialRule> rules = spatialRuleService.findActiveRulesForArea(areaCode, RuleCategory.ACCESS_CONTROL);
            log.debug("找到 {} 个适用的准入控制规则", rules.size());
            
            // 4. 执行规则检查
            return executeAccessRules(vehicle, area, rules);
            
        } catch (Exception e) {
            log.error("电子围栏检测失败: 无人车={}, 区域={}", vehicle.getObjectId(), areaCode, e);
            return GeofenceAccessCheckResult.denied(areaCode, vehicle.getObjectId(), "系统检测失败: " + e.getMessage());
        }
    }
    
    /**
     * 检测无人车当前位置是否触发电子围栏
     * 
     * @param vehicle 无人车对象
     * @return 检测结果列表（可能进入多个区域）
     */
    public List<GeofenceAccessCheckResult> checkCurrentPosition(MovingObject vehicle) {
        List<GeofenceAccessCheckResult> results = new ArrayList<>();
        
        // 类型检查：只处理无人车
        if (vehicle.getObjectType() != MovingObjectType.UNMANNED_VEHICLE) {
            log.debug("跳过非无人车位置检测: {}", vehicle.getObjectId());
            results.add(GeofenceAccessCheckResult.skipped(vehicle.getObjectId()));
            return results;
        }
        
        try {
            Point currentPosition = vehicle.getCurrentPosition();
            if (currentPosition == null) {
                log.warn("无人车位置信息为空: {}", vehicle.getObjectId());
                return results;
            }
            
            // 查找当前位置所在的所有区域
            List<AirportArea> containingAreas = airportAreaService.findAreasContainingPoint(currentPosition);
            log.debug("无人车 {} 当前位置包含在 {} 个区域中", vehicle.getObjectId(), containingAreas.size());
            
            // 对每个区域进行检测
            for (AirportArea area : containingAreas) {
                GeofenceAccessCheckResult result = checkAreaAccess(vehicle, area.getAreaId());
                results.add(result);
                
                // 发布事件
                publishGeofenceEvent(vehicle, area, result);
            }
            
            return results;
            
        } catch (Exception e) {
            log.error("位置检测失败: 无人车={}", vehicle.getObjectId(), e);
            results.add(GeofenceAccessCheckResult.denied(null, vehicle.getObjectId(), "位置检测失败: " + e.getMessage()));
            return results;
        }
    }
    
    /**
     * 执行准入控制规则
     */
    private GeofenceAccessCheckResult executeAccessRules(MovingObject vehicle, AirportArea area, List<SpatialRule> rules) {
        List<GeofenceAccessCheckResult.TriggeredRule> triggeredRules = new ArrayList<>();
        RuleAlertLevel maxAlertLevel = RuleAlertLevel.INFO;
        boolean accessDenied = false;
        String denyReason = null;
        
        // 如果没有规则，默认允许
        if (rules.isEmpty()) {
            log.debug("区域 {} 没有准入控制规则，默认允许", area.getAreaId());
            return GeofenceAccessCheckResult.allowed(area.getAreaId(), vehicle.getObjectId());
        }
        
        // 按优先级排序规则
        rules.sort((r1, r2) -> Integer.compare(r1.getPriority(), r2.getPriority()));
        
        for (SpatialRule rule : rules) {
            try {
                // 检查规则是否当前有效
                if (!rule.isCurrentlyEffective()) {
                    log.debug("规则 {} 当前不生效，跳过", rule.getRuleId());
                    continue;
                }
                
                // 检查车辆类型是否被允许
                if (!rule.isVehicleTypeAllowed(vehicle.getObjectType())) {
                    log.debug("规则 {} 不允许车辆类型 {}", rule.getRuleId(), vehicle.getObjectType());
                    continue;
                }
                
                // 执行具体规则检查
                RuleCheckResult checkResult = checkSpecificRule(vehicle, area, rule);
                
                if (!checkResult.passed) {
                    // 规则检查失败
                    GeofenceAccessCheckResult.TriggeredRule triggeredRule = GeofenceAccessCheckResult.TriggeredRule.builder()
                            .ruleId(rule.getRuleId())
                            .ruleName(rule.getName())
                            .ruleCategory(rule.getCategory().getDisplayName())
                            .violationType(checkResult.violationType)
                            .alertLevel(rule.getAlertLevel())
                            .message(checkResult.message)
                            .parameters(rule.getParameters())
                            .build();
                    
                    triggeredRules.add(triggeredRule);
                    
                    // 更新最高告警级别
                    if (rule.getAlertLevel().isHigherOrEqual(maxAlertLevel)) {
                        maxAlertLevel = rule.getAlertLevel();
                    }
                    
                    // 检查是否需要拒绝访问
                    if (rule.getAlertLevel().isHigherOrEqual(RuleAlertLevel.CRITICAL)) {
                        accessDenied = true;
                        denyReason = checkResult.message;
                    }
                }
                
            } catch (Exception e) {
                log.error("规则检查失败: 规则ID={}, 无人车={}", rule.getRuleId(), vehicle.getObjectId(), e);
            }
        }
        
        // 构建检测结果
        GeofenceAccessCheckResult.GeofenceAccessCheckResultBuilder resultBuilder = GeofenceAccessCheckResult.builder()
                .areaCode(area.getAreaId())
                .areaName(area.getName())
                .vehicleId(vehicle.getObjectId())
                .triggeredRules(triggeredRules)
                .alertLevel(maxAlertLevel)
                .checkTime(LocalDateTime.now());
        
        if (accessDenied) {
            return resultBuilder
                    .resultType(GeofenceAccessCheckResult.AccessResultType.DENIED)
                    .allowed(false)
                    .message("拒绝进入")
                    .reason(denyReason)
                    .build();
        } else if (!triggeredRules.isEmpty()) {
            return resultBuilder
                    .resultType(GeofenceAccessCheckResult.AccessResultType.WARNING)
                    .allowed(true)
                    .message("允许进入但有警告")
                    .build();
        } else {
            return resultBuilder
                    .resultType(GeofenceAccessCheckResult.AccessResultType.ALLOWED)
                    .allowed(true)
                    .message("允许进入")
                    .build();
        }
    }
    
    /**
     * 检查具体规则
     */
    private RuleCheckResult checkSpecificRule(MovingObject vehicle, AirportArea area, SpatialRule rule) {
        try {
            // 解析规则配置
            UnmannedVehicleGeofenceRuleConfig config = parseRuleConfig(rule.getParameters());
            
            // 检查准入控制
            if (config.getAccessControl() != null) {
                RuleCheckResult accessResult = checkAccessControl(vehicle, config.getAccessControl());
                if (!accessResult.passed) {
                    return accessResult;
                }
            }
            
            // 检查物理限制
            if (config.getPhysicalLimits() != null) {
                RuleCheckResult physicalResult = checkPhysicalLimits(vehicle, config.getPhysicalLimits());
                if (!physicalResult.passed) {
                    return physicalResult;
                }
            }
            
            // 检查时间限制
            if (config.getTimeRestrictions() != null) {
                RuleCheckResult timeResult = checkTimeRestrictions(config.getTimeRestrictions());
                if (!timeResult.passed) {
                    return timeResult;
                }
            }
            
            // 检查安全要求
            if (config.getSafetyRequirements() != null) {
                RuleCheckResult safetyResult = checkSafetyRequirements(vehicle, config.getSafetyRequirements());
                if (!safetyResult.passed) {
                    return safetyResult;
                }
            }
            
            return RuleCheckResult.passed();
            
        } catch (Exception e) {
            log.error("规则检查异常: 规则ID={}", rule.getRuleId(), e);
            return RuleCheckResult.failed("规则检查异常: " + e.getMessage(), "SYSTEM_ERROR");
        }
    }
    
    /**
     * 解析规则配置
     */
    private UnmannedVehicleGeofenceRuleConfig parseRuleConfig(String parameters) {
        if (parameters == null || parameters.trim().isEmpty()) {
            return UnmannedVehicleGeofenceRuleConfig.builder().build();
        }
        
        try {
            return objectMapper.readValue(parameters, UnmannedVehicleGeofenceRuleConfig.class);
        } catch (JsonProcessingException e) {
            log.warn("解析规则配置失败，使用默认配置: {}", e.getMessage());
            return UnmannedVehicleGeofenceRuleConfig.builder().build();
        }
    }
    
    /**
     * 检查准入控制
     */
    private RuleCheckResult checkAccessControl(MovingObject vehicle, UnmannedVehicleGeofenceRuleConfig.AccessControlConfig config) {
        // 检查权限要求
        if (Boolean.TRUE.equals(config.getRequiresPermission())) {
            // TODO: 实现权限检查逻辑
            log.debug("需要权限验证，暂未实现");
        }
        
        // 检查操作模式
        if (config.getAllowedOperationModes() != null && !config.getAllowedOperationModes().isEmpty()) {
            // TODO: 检查无人车当前操作模式
            log.debug("检查操作模式限制");
        }
        
        return RuleCheckResult.passed();
    }
    
    /**
     * 检查物理限制
     */
    private RuleCheckResult checkPhysicalLimits(MovingObject vehicle, UnmannedVehicleGeofenceRuleConfig.PhysicalLimitsConfig config) {
        // 检查速度限制
        if (config.getMaxSpeed() != null && vehicle.getCurrentSpeed() != null) {
            if (vehicle.getCurrentSpeed() > config.getMaxSpeed()) {
                return RuleCheckResult.failed(
                        String.format("超速限制: 当前速度%.1f km/h，限制%.1f km/h", 
                                vehicle.getCurrentSpeed(), config.getMaxSpeed()),
                        "SPEED"
                );
            }
        }
        
        // TODO: 检查其他物理限制（高度、重量等）
        
        return RuleCheckResult.passed();
    }
    
    /**
     * 检查时间限制
     */
    private RuleCheckResult checkTimeRestrictions(UnmannedVehicleGeofenceRuleConfig.TimeRestrictionsConfig config) {
        // 检查活跃时间段
        if (config.getActiveHours() != null) {
            // TODO: 解析时间段格式 "06:00-22:00" 并检查
            log.debug("检查活跃时间段: {}", config.getActiveHours());
        }
        
        // TODO: 检查其他时间限制
        
        return RuleCheckResult.passed();
    }
    
    /**
     * 检查安全要求
     */
    private RuleCheckResult checkSafetyRequirements(MovingObject vehicle, UnmannedVehicleGeofenceRuleConfig.SafetyRequirementsConfig config) {
        // 检查电池电量
        if (config.getMinBatteryLevel() != null) {
            // TODO: 获取无人车电池电量并检查
            log.debug("检查电池电量要求: 最低{}%", config.getMinBatteryLevel());
        }
        
        // TODO: 检查其他安全要求
        
        return RuleCheckResult.passed();
    }
    
    /**
     * 发布围栏事件
     */
    private void publishGeofenceEvent(MovingObject vehicle, AirportArea area, GeofenceAccessCheckResult result) {
        try {
            // 只发布需要告警的事件（拒绝、警告）
            if (result.getResultType() == GeofenceAccessCheckResult.AccessResultType.DENIED ||
                result.getResultType() == GeofenceAccessCheckResult.AccessResultType.WARNING) {
                
                // 创建WebSocket载荷
                GeofenceAlertPayload payload = GeofenceAlertPayload.fromGeofenceResult(
                    result,
                    vehicle.getObjectName(),
                    vehicle.getCurrentPosition() != null ? vehicle.getCurrentPosition().getY() : null,
                    vehicle.getCurrentPosition() != null ? vehicle.getCurrentPosition().getX() : null,
                    vehicle.getAltitude(),
                    vehicle.getCurrentSpeed()
                );
                
                // 创建并发布WebSocket事件
                GeofenceAlertWebSocketEvent event = GeofenceAlertWebSocketEvent.create(payload);
                eventPublisher.publishEvent(event);
                
                log.info("发布电子围栏告警WebSocket事件: 无人车={}, 区域={}, 类型={}, 级别={}", 
                        vehicle.getObjectId(), area.getAreaId(), result.getResultType(), result.getAlertLevel());
            } else {
                log.debug("无人车 {} 正常通过区域 {}，无需发布告警", vehicle.getObjectId(), area.getAreaId());
            }
            
        } catch (Exception e) {
            log.error("发布围栏WebSocket事件失败: 无人车={}, 区域={}", 
                    vehicle.getObjectId(), area.getAreaId(), e);
        }
    }
    
    /**
     * 规则检查结果内部类
     */
    private static class RuleCheckResult {
        final boolean passed;
        final String message;
        final String violationType;
        
        private RuleCheckResult(boolean passed, String message, String violationType) {
            this.passed = passed;
            this.message = message;
            this.violationType = violationType;
        }
        
        static RuleCheckResult passed() {
            return new RuleCheckResult(true, null, null);
        }
        
        static RuleCheckResult failed(String message, String violationType) {
            return new RuleCheckResult(false, message, violationType);
        }
    }
}