using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using MultiWheelC.TrajectoryPlanning.PathSmoothing.Processing;
using MultiWheelC.TrajectoryPlanning.Utils;

namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.LocalG2;

/// <summary>一个尚未经过安全和质量评价的局部 G2 替换几何。</summary>
internal sealed class LocalG2CandidateGeometry
{
    /// <summary>创建尚未通过安全与质量门的局部 G2 候选几何快照。</summary>
    /// <param name="candidateIndex">区域内候选的稳定从零开始索引。</param>
    /// <param name="segmentIndex">候选所属方向段索引。</param>
    /// <param name="startArcLengthMeters">替换窗口起点弧长，单位 m。</param>
    /// <param name="endArcLengthMeters">替换窗口终点弧长，单位 m。</param>
    /// <param name="leftWindowLengthMeters">过渡点左侧窗口长度，单位 m。</param>
    /// <param name="rightWindowLengthMeters">过渡点右侧窗口长度，单位 m。</param>
    /// <param name="regionPoints">含精确边界端点的候选采样点只读集合。</param>
    /// <param name="startVehicleCurvaturePerMeter">窗口起点车辆曲率，单位 1/m。</param>
    /// <param name="endVehicleCurvaturePerMeter">窗口终点车辆曲率，单位 1/m。</param>
    /// <param name="startGeometricCurvaturePerMeter">窗口起点几何曲率，单位 1/m。</param>
    /// <param name="endGeometricCurvaturePerMeter">窗口终点几何曲率，单位 1/m。</param>
    /// <param name="internalConnectionsAreG2">候选内部连接是否满足 G2 连续性。</param>
    internal LocalG2CandidateGeometry(
        int candidateIndex,
        int segmentIndex,
        double startArcLengthMeters,
        double endArcLengthMeters,
        double leftWindowLengthMeters,
        double rightWindowLengthMeters,
        IReadOnlyList<SmoothingPoint2D> regionPoints,
        double startVehicleCurvaturePerMeter,
        double endVehicleCurvaturePerMeter,
        double startGeometricCurvaturePerMeter,
        double endGeometricCurvaturePerMeter,
        bool internalConnectionsAreG2)
    {
        if (candidateIndex < 0 || segmentIndex < 0 || !NumericGuard.IsFinite(startArcLengthMeters) ||
            !NumericGuard.IsFinite(endArcLengthMeters) || startArcLengthMeters < 0d ||
            endArcLengthMeters < startArcLengthMeters || !NumericGuard.IsFinite(leftWindowLengthMeters) ||
            !NumericGuard.IsFinite(rightWindowLengthMeters) || leftWindowLengthMeters < 0d ||
            rightWindowLengthMeters < 0d || regionPoints == null || regionPoints.Count < 2 ||
            !NumericGuard.IsFinite(startVehicleCurvaturePerMeter) || !NumericGuard.IsFinite(endVehicleCurvaturePerMeter) ||
            !NumericGuard.IsFinite(startGeometricCurvaturePerMeter) || !NumericGuard.IsFinite(endGeometricCurvaturePerMeter))
        {
            throw new ArgumentOutOfRangeException(nameof(regionPoints));
        }

        CandidateIndex = candidateIndex;
        SegmentIndex = segmentIndex;
        StartArcLengthMeters = startArcLengthMeters;
        EndArcLengthMeters = endArcLengthMeters;
        LeftWindowLengthMeters = leftWindowLengthMeters;
        RightWindowLengthMeters = rightWindowLengthMeters;
        RegionPoints = Copy(regionPoints);
        StartVehicleCurvaturePerMeter = startVehicleCurvaturePerMeter;
        EndVehicleCurvaturePerMeter = endVehicleCurvaturePerMeter;
        StartGeometricCurvaturePerMeter = startGeometricCurvaturePerMeter;
        EndGeometricCurvaturePerMeter = endGeometricCurvaturePerMeter;
        InternalConnectionsAreG2 = internalConnectionsAreG2;
    }

    internal int CandidateIndex { get; }
    internal int SegmentIndex { get; }
    internal double StartArcLengthMeters { get; }
    internal double EndArcLengthMeters { get; }
    internal double LeftWindowLengthMeters { get; }
    internal double RightWindowLengthMeters { get; }
    internal IReadOnlyList<SmoothingPoint2D> RegionPoints { get; }

    // 这些边界状态供候选评价和窄范围反射验证使用，不能替代统一几何分析器的最终统计。
    internal double StartVehicleCurvaturePerMeter { get; }
    internal double EndVehicleCurvaturePerMeter { get; }
    internal double StartGeometricCurvaturePerMeter { get; }
    internal double EndGeometricCurvaturePerMeter { get; }
    internal bool InternalConnectionsAreG2 { get; }

    private static IReadOnlyList<SmoothingPoint2D> Copy(IReadOnlyList<SmoothingPoint2D> source)
    {
        var copy = new List<SmoothingPoint2D>(source.Count);
        for (int index = 0; index < source.Count; index++)
        {
            if (source[index] == null) throw new ArgumentOutOfRangeException(nameof(source));
            copy.Add(source[index]);
        }
        return new ReadOnlyCollection<SmoothingPoint2D>(copy);
    }
}
