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

namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.LocalG2;

/// <summary>一个局部 G2 候选可替换的弧长窗口。</summary>
internal sealed class LocalG2WindowVariant
{
    /// <summary>创建同一平滑区域内一个可尝试替换的弧长窗口变体。</summary>
    /// <param name="candidateIndex">区域内候选的稳定从零开始索引。</param>
    /// <param name="startArcLengthMeters">窗口起点弧长，单位 m。</param>
    /// <param name="endArcLengthMeters">窗口终点弧长，单位 m。</param>
    /// <param name="leftWindowLengthMeters">过渡点左侧窗口长度，单位 m。</param>
    /// <param name="rightWindowLengthMeters">过渡点右侧窗口长度，单位 m。</param>
    internal LocalG2WindowVariant(int candidateIndex, double startArcLengthMeters, double endArcLengthMeters,
        double leftWindowLengthMeters, double rightWindowLengthMeters)
    {
        if (candidateIndex < 0 || startArcLengthMeters < 0d || endArcLengthMeters < startArcLengthMeters ||
            leftWindowLengthMeters < 0d || rightWindowLengthMeters < 0d)
        {
            throw new ArgumentOutOfRangeException(nameof(candidateIndex));
        }
        CandidateIndex = candidateIndex;
        StartArcLengthMeters = startArcLengthMeters;
        EndArcLengthMeters = endArcLengthMeters;
        LeftWindowLengthMeters = leftWindowLengthMeters;
        RightWindowLengthMeters = rightWindowLengthMeters;
    }

    internal int CandidateIndex { get; }
    internal double StartArcLengthMeters { get; }
    internal double EndArcLengthMeters { get; }
    internal double LeftWindowLengthMeters { get; }
    internal double RightWindowLengthMeters { get; }
}

/// <summary>至少存在一个联合合法生成窗口变体的一组曲率过渡。</summary>
internal sealed class LocalG2SmoothingRegion
{
    /// <summary>创建一个包含共同可用窗口变体的局部曲率过渡区域。</summary>
    /// <param name="segmentIndex">所属方向段在预处理路径中的从零开始索引。</param>
    /// <param name="transitions">归并到该区域的曲率跳变集合。</param>
    /// <param name="maximumStartArcLengthMeters">所有候选允许的最晚窗口起点，单位 m。</param>
    /// <param name="maximumEndArcLengthMeters">所有候选允许的最早窗口终点，单位 m。</param>
    /// <param name="windowVariants">至少一个合法的窗口变体集合。</param>
    internal LocalG2SmoothingRegion(
        int segmentIndex,
        IReadOnlyList<CurvatureTransition> transitions,
        double maximumStartArcLengthMeters,
        double maximumEndArcLengthMeters,
        IReadOnlyList<LocalG2WindowVariant> windowVariants)
    {
        if (segmentIndex < 0 || transitions == null || transitions.Count == 0 ||
            !NumericGuard.IsFinite(maximumStartArcLengthMeters) ||
            !NumericGuard.IsFinite(maximumEndArcLengthMeters) ||
            maximumStartArcLengthMeters < 0d ||
            maximumEndArcLengthMeters < maximumStartArcLengthMeters ||
            windowVariants == null || windowVariants.Count == 0)
        {
            throw new ArgumentOutOfRangeException(nameof(transitions));
        }
        SegmentIndex = segmentIndex;
        Transitions = Copy(transitions);
        MaximumStartArcLengthMeters = maximumStartArcLengthMeters;
        MaximumEndArcLengthMeters = maximumEndArcLengthMeters;
        WindowVariants = Copy(windowVariants);
    }

    internal int SegmentIndex { get; }
    internal IReadOnlyList<CurvatureTransition> Transitions { get; }
    internal double MaximumStartArcLengthMeters { get; }
    internal double MaximumEndArcLengthMeters { get; }
    internal IReadOnlyList<LocalG2WindowVariant> WindowVariants { get; }

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