using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using CounterDrone.Core.Models;
namespace CounterDrone.Core.Algorithms
{
/// 防御规划器配置 — 全局策略参数,从 planner_config.json 加载。
/// 代码零默认值,所有字段必须从配置文件读取;文件缺失或字段缺失即抛异常。
public class PlannerConfig
{
/// 云团重叠比例(0=相切,0.2=重叠 20%)。间距 = 2R × (1 − 重叠比例)。
public float CloudOverlapRatio { get; set; }
/// 临界方案概率阈值(DeriveCritical 用)
public float CriticalProbabilityThreshold { get; set; }
/// 拦截概率上限(封顶值)
public float MaxInterceptProbability { get; set; }
/// 威胁类型系数表(TargetType → 系数)
public Dictionary TypeCoefficient { get; set; } = new();
/// 弹药匹配表(PowerType → AerosolType)
public Dictionary AmmoMatch { get; set; } = new();
/// 无探测设备时的默认探测精度 m(回退值,上帝视角但有标称误差)
public float DefaultDetectionAccuracy { get; set; }
/// 云团有效膨胀系数(0~1)。planner 取 Phase 2 膨胀时间的此比例作为有效云团年龄。默认 0.9
public float ExpansionFactor { get; set; } = 0.9f;
/// 拦截窗口安全余量(s)。计算所需探测弧长时在膨胀时间基础上额外预留。默认 1
public float TimingSafetyMargin { get; set; } = 1f;
private const string ConfigFileName = "planner_config.json";
/// 从 dataRoot 加载配置。文件缺失或字段非法即抛异常。
public static PlannerConfig Load(string dataRoot)
{
if (string.IsNullOrEmpty(dataRoot))
throw new ArgumentException("dataRoot 不能为空", nameof(dataRoot));
string path = Path.Combine(dataRoot, ConfigFileName);
if (!File.Exists(path))
throw new FileNotFoundException($"planner 配置文件不存在: {path}");
string json = File.ReadAllText(path);
var config = JsonSerializer.Deserialize(json, JsonOptions)
?? throw new InvalidDataException($"planner 配置解析失败: {path}");
config.Validate();
return config;
}
/// 从 IPathProvider 加载(便捷重载)
public static PlannerConfig Load(IPathProvider paths)
=> Load(paths?.GetDataRoot() ?? throw new ArgumentNullException(nameof(paths)));
private void Validate()
{
if (CloudOverlapRatio < 0f || CloudOverlapRatio >= 1f)
throw new InvalidDataException($"CloudOverlapRatio 必须在 [0, 1),实际 {CloudOverlapRatio}");
if (CriticalProbabilityThreshold <= 0f || CriticalProbabilityThreshold >= 1f)
throw new InvalidDataException($"CriticalProbabilityThreshold 必须在 (0, 1),实际 {CriticalProbabilityThreshold}");
if (MaxInterceptProbability <= 0f || MaxInterceptProbability > 1f)
throw new InvalidDataException($"MaxInterceptProbability 必须在 (0, 1],实际 {MaxInterceptProbability}");
if (TypeCoefficient == null || TypeCoefficient.Count == 0)
throw new InvalidDataException("TypeCoefficient 不能为空");
if (AmmoMatch == null || AmmoMatch.Count == 0)
throw new InvalidDataException("AmmoMatch 不能为空");
if (DefaultDetectionAccuracy < 0f)
throw new InvalidDataException($"DefaultDetectionAccuracy 必须 >= 0,实际 {DefaultDetectionAccuracy}");
if (ExpansionFactor <= 0f || ExpansionFactor > 1f)
throw new InvalidDataException($"ExpansionFactor 必须在 (0, 1],实际 {ExpansionFactor}");
if (TimingSafetyMargin < 0f)
throw new InvalidDataException($"TimingSafetyMargin 必须 >= 0,实际 {TimingSafetyMargin}");
}
private static readonly JsonSerializerOptions JsonOptions = new()
{
Converters = { new JsonStringEnumConverter() },
PropertyNameCaseInsensitive = true,
};
}
}