using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace MultiWheelC.TrajectoryPlanning.PathSmoothing;

/// <summary>单个局部 G2 平滑区域的不可变发布报告。</summary>
public sealed class PathSmoothingRegionReport
{
    /// <summary>创建单个局部 G2 区域的不可变处理报告。</summary>
    /// <param name="segmentIndex">所属方向段的从零开始索引。</param>
    /// <param name="startArcLengthMeters">区域在完整路径上的起始弧长，单位 m。</param>
    /// <param name="endArcLengthMeters">区域在完整路径上的结束弧长，单位 m。</param>
    /// <param name="curvatureJumpsPerMeter">触发该区域的曲率跳变只读副本，单位 1/m。</param>
    /// <param name="plannedWindowLengthMeters">规划窗口长度，单位 m。</param>
    /// <param name="actualWindowLengthMeters">实际参与平滑的窗口长度，单位 m。</param>
    /// <param name="leftWindowLengthMeters">锚点左侧窗口长度，单位 m。</param>
    /// <param name="rightWindowLengthMeters">锚点右侧窗口长度，单位 m。</param>
    /// <param name="candidateCount">已评估候选数量。</param>
    /// <param name="selectedCandidateIndex">改进时选中候选索引；未改进时结果固定为 -1。</param>
    /// <param name="status">区域是替换为改进候选还是保留原始几何。</param>
    /// <param name="failureReason">未替换原始几何时的稳定拒绝原因。</param>
    /// <param name="rawPeakCurvatureDerivativePerSquareMeter">原始峰值曲率导数，单位 1/m²。</param>
    /// <param name="resultPeakCurvatureDerivativePerSquareMeter">结果峰值曲率导数，单位 1/m²。</param>
    /// <param name="rawCurvatureVariationCost">原始曲率变化代价。</param>
    /// <param name="resultCurvatureVariationCost">结果曲率变化代价。</param>
    /// <param name="maximumDeviationMeters">候选相对原始路径最大偏移，单位 m。</param>
    /// <param name="minimumBodyClearanceMeters">扩大车体最小保守净空，单位 m。</param>
    /// <param name="maximumAbsoluteVehicleCurvaturePerMeter">绝对车辆曲率峰值，单位 1/m。</param>
    public PathSmoothingRegionReport(
        int segmentIndex,
        double startArcLengthMeters,
        double endArcLengthMeters,
        IReadOnlyList<double> curvatureJumpsPerMeter,
        double plannedWindowLengthMeters,
        double actualWindowLengthMeters,
        double leftWindowLengthMeters,
        double rightWindowLengthMeters,
        int candidateCount,
        int selectedCandidateIndex,
        PathSmoothingRegionStatus status,
        PathSmoothingRegionFailureReason failureReason,
        double rawPeakCurvatureDerivativePerSquareMeter,
        double resultPeakCurvatureDerivativePerSquareMeter,
        double rawCurvatureVariationCost,
        double resultCurvatureVariationCost,
        double maximumDeviationMeters,
        double minimumBodyClearanceMeters,
        double maximumAbsoluteVehicleCurvaturePerMeter)
    {
        SegmentIndex = segmentIndex;
        StartArcLengthMeters = startArcLengthMeters;
        EndArcLengthMeters = endArcLengthMeters;
        CurvatureJumpsPerMeter = CopyReadOnly(curvatureJumpsPerMeter);
        PlannedWindowLengthMeters = plannedWindowLengthMeters;
        ActualWindowLengthMeters = actualWindowLengthMeters;
        LeftWindowLengthMeters = leftWindowLengthMeters;
        RightWindowLengthMeters = rightWindowLengthMeters;
        CandidateCount = candidateCount;
        SelectedCandidateIndex = status == PathSmoothingRegionStatus.Improved
            ? selectedCandidateIndex
            : -1;
        Status = status;
        FailureReason = failureReason;
        RawPeakCurvatureDerivativePerSquareMeter = rawPeakCurvatureDerivativePerSquareMeter;
        ResultPeakCurvatureDerivativePerSquareMeter = resultPeakCurvatureDerivativePerSquareMeter;
        RawCurvatureVariationCost = rawCurvatureVariationCost;
        ResultCurvatureVariationCost = resultCurvatureVariationCost;
        MaximumDeviationMeters = maximumDeviationMeters;
        MinimumBodyClearanceMeters = minimumBodyClearanceMeters;
        MaximumAbsoluteVehicleCurvaturePerMeter = maximumAbsoluteVehicleCurvaturePerMeter;
    }

    public int SegmentIndex { get; }
    public double StartArcLengthMeters { get; }
    public double EndArcLengthMeters { get; }
    public IReadOnlyList<double> CurvatureJumpsPerMeter { get; }
    public double PlannedWindowLengthMeters { get; }
    public double ActualWindowLengthMeters { get; }
    public double LeftWindowLengthMeters { get; }
    public double RightWindowLengthMeters { get; }
    public int CandidateCount { get; }
    public int SelectedCandidateIndex { get; }
    public PathSmoothingRegionStatus Status { get; }
    public PathSmoothingRegionFailureReason FailureReason { get; }
    public double RawPeakCurvatureDerivativePerSquareMeter { get; }
    public double ResultPeakCurvatureDerivativePerSquareMeter { get; }
    public double RawCurvatureVariationCost { get; }
    public double ResultCurvatureVariationCost { get; }
    public double MaximumDeviationMeters { get; }
    public double MinimumBodyClearanceMeters { get; }
    public double MaximumAbsoluteVehicleCurvaturePerMeter { get; }

    private static IReadOnlyList<double> CopyReadOnly(IReadOnlyList<double> source)
    {
        var copy = new List<double>(source == null ? 0 : source.Count);
        if (source != null)
        {
            for (int index = 0; index < source.Count; index++)
                copy.Add(source[index]);
        }
        return new ReadOnlyCollection<double>(copy);
    }
}
