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

namespace MultiWheelC.TrajectoryPlanning.CoarsePath;

/// <summary>
/// 一次粗路径规划的最终不可变结果。
/// 只有 <see cref="Status"/> 为 <see cref="PlanningStatus.Success"/> 时才携带非空路径与方向分段；其他状态始终返回空只读集合。
/// </summary>
public sealed class PlanningResult
{
    private static readonly IReadOnlyList<CoarsePathPoint> EmptyPath = new ReadOnlyCollection<CoarsePathPoint>(new List<CoarsePathPoint>());
    private static readonly IReadOnlyList<PathSegment> EmptySegments = new ReadOnlyCollection<PathSegment>(new List<PathSegment>());

    private PlanningResult(PlanningStatus status, PlanningDiagnostics diagnostics, IReadOnlyList<CoarsePathPoint> path, IReadOnlyList<PathSegment> segments)
    {
        Status = status;
        Diagnostics = diagnostics ?? new PlanningDiagnostics(terminationReason: "未提供诊断信息。");
        Path = path;
        Segments = segments;
    }

    /// <summary>规划最终状态；只有 <see cref="PlanningStatus.Success"/> 可以发布路径。</summary>
    public PlanningStatus Status { get; }

    /// <summary>节点、耗时、路径长度、净空和终止原因统计；始终非空。</summary>
    public PlanningDiagnostics Diagnostics { get; }

    /// <summary>成功时的稠密粗路径；失败时为不可修改的空集合。</summary>
    public IReadOnlyList<CoarsePathPoint> Path { get; }

    /// <summary>成功时覆盖 <see cref="Path"/> 的包含式方向分段；失败时为不可修改的空集合。</summary>
    public IReadOnlyList<PathSegment> Segments { get; }

    /// <summary>
    /// 创建成功结果。
    /// 参数：path 与 segments 必须均为非空；diagnostics 为本次规划的统计快照。参数不符合要求时抛出 <see cref="ArgumentException"/>，防止以成功状态发布不完整路径。
    /// </summary>
    public static PlanningResult Success(IReadOnlyList<CoarsePathPoint> path, IReadOnlyList<PathSegment> segments, PlanningDiagnostics diagnostics)
    {
        if (path == null || path.Count == 0)
            throw new ArgumentException("Successful planning results require a non-empty path.", nameof(path));
        if (segments == null || segments.Count == 0)
            throw new ArgumentException("Successful planning results require non-empty segments.", nameof(segments));
        return new PlanningResult(PlanningStatus.Success, diagnostics, CopyReadOnly(path), CopyReadOnly(segments));
    }

    /// <summary>
    /// 创建失败、取消或资源受限结果。
    /// 参数：status 不能为 <see cref="PlanningStatus.Success"/>；diagnostics 会原样保留。返回结果的路径与分段始终为空只读集合。
    /// </summary>
    public static PlanningResult Failure(PlanningStatus status, PlanningDiagnostics diagnostics)
    {
        if (status == PlanningStatus.Success)
            throw new ArgumentException("Use Success to create a successful planning result.", nameof(status));
        return new PlanningResult(status, diagnostics, EmptyPath, EmptySegments);
    }

    private static IReadOnlyList<T> CopyReadOnly<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);
    }
}
