using System;
using MultiWheelC.TrajectoryPlanning.Utils;

namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.Algorithms;

/// <summary>供单次平滑算法运行使用的、已校验的不可变方法选项快照。</summary>
internal sealed class SmoothingOptionsSnapshot
{
    internal SmoothingOptionsSnapshot(PathSmoothingConfiguration configuration)
    {
        if (configuration == null) throw new ArgumentNullException(nameof(configuration));

        CubicBSplineEndpointTangentScale = configuration.CubicBSpline.EndpointTangentScale;
        BezierCornerHeadingThresholdRadians = configuration.LocalCubicBezier.CornerHeadingThresholdRadians;
        BezierMaximumWindowLengthMeters = configuration.LocalCubicBezier.MaximumWindowLengthMeters;
        BezierHandleLengthRatio = configuration.LocalCubicBezier.HandleLengthRatio;
        QuinticKnotSpacingMeters = configuration.PiecewiseQuintic.KnotSpacingMeters;
        QuinticMinimumKnotSpacingMeters = configuration.PiecewiseQuintic.MinimumKnotSpacingMeters;

        ValidatePositiveFinite(CubicBSplineEndpointTangentScale, nameof(CubicBSplineEndpointTangentScale));
        if (!NumericGuard.IsFinite(BezierCornerHeadingThresholdRadians) ||
            BezierCornerHeadingThresholdRadians <= 0d || BezierCornerHeadingThresholdRadians > Math.PI)
        {
            throw new ArgumentOutOfRangeException(nameof(BezierCornerHeadingThresholdRadians));
        }
        ValidatePositiveFinite(BezierMaximumWindowLengthMeters, nameof(BezierMaximumWindowLengthMeters));
        ValidatePositiveFinite(BezierHandleLengthRatio, nameof(BezierHandleLengthRatio));
        ValidatePositiveFinite(QuinticKnotSpacingMeters, nameof(QuinticKnotSpacingMeters));
        ValidatePositiveFinite(QuinticMinimumKnotSpacingMeters, nameof(QuinticMinimumKnotSpacingMeters));
        if (QuinticKnotSpacingMeters < QuinticMinimumKnotSpacingMeters)
            throw new ArgumentOutOfRangeException(nameof(QuinticKnotSpacingMeters));
    }

    internal double CubicBSplineEndpointTangentScale { get; }

    internal double BezierCornerHeadingThresholdRadians { get; }

    internal double BezierMaximumWindowLengthMeters { get; }

    internal double BezierHandleLengthRatio { get; }

    internal double QuinticKnotSpacingMeters { get; }

    internal double QuinticMinimumKnotSpacingMeters { get; }

    private static void ValidatePositiveFinite(double value, string name)
    {
        if (!NumericGuard.IsPositiveFinite(value)) throw new ArgumentOutOfRangeException(name);
    }
}
