using System.Collections.Generic;
using System.Collections.ObjectModel;
using MultiWheelC.TrajectoryPlanning.CoarsePath;
using Newtonsoft.Json;

namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.Test;

/// <summary>一个可复现的快速粗路径夹具及其地图、车辆和方向段快照。</summary>
public sealed class SmoothingScenarioFixture
{
    internal SmoothingScenarioFixture(SmoothingFixtureRecord record, bool fingerprintCurrent)
    {
        Record = record;
        Id = record.Id;
        FixtureVersion = record.FixtureVersion;
        ConfigurationFingerprint = record.ConfigurationFingerprint;
        IsConfigurationFingerprintCurrent = fingerprintCurrent;
        Path = ToPath(record.Path);
        Segments = ToSegments(record.Segments);
    }

    /// <summary>稳定英文场景标识。</summary>
    public string Id { get; }
    /// <summary>夹具自身的正版本号。</summary>
    public int FixtureVersion { get; }
    /// <summary>由夹具输入生成的稳定 SHA-256 指纹。</summary>
    public string ConfigurationFingerprint { get; }
    /// <summary>存储指纹是否与当前夹具内容一致。</summary>
    public bool IsConfigurationFingerprintCurrent { get; }
    /// <summary>快速比较使用的不可变粗路径点。</summary>
    public IReadOnlyList<CoarsePathPoint> Path { get; }
    /// <summary>覆盖粗路径的不可变方向段。</summary>
    public IReadOnlyList<PathSegment> Segments { get; }

    internal SmoothingFixtureRecord Record { get; }

    private static IReadOnlyList<CoarsePathPoint> ToPath(IReadOnlyList<SmoothingFixturePathPoint> source)
    {
        var result = new List<CoarsePathPoint>(source.Count);
        for (int index = 0; index < source.Count; index++)
        {
            SmoothingFixturePathPoint point = source[index];
            result.Add(new CoarsePathPoint(
                point.XMeters, point.YMeters, point.HeadingRadians, point.UnwrappedHeadingRadians,
                point.ArcLengthMeters, point.Direction, point.VehicleCurvaturePerMeter,
                point.BodyClearanceMeters, point.IsGearSwitchPoint, point.Source));
        }
        return new ReadOnlyCollection<CoarsePathPoint>(result);
    }

    private static IReadOnlyList<PathSegment> ToSegments(IReadOnlyList<SmoothingFixtureSegment> source)
    {
        var result = new List<PathSegment>(source.Count);
        for (int index = 0; index < source.Count; index++)
        {
            SmoothingFixtureSegment segment = source[index];
            result.Add(new PathSegment(segment.SegmentIndex, segment.Direction, segment.StartIndex, segment.EndIndex,
                segment.StartsAtGearSwitch, segment.EndsAtGearSwitch));
        }
        return new ReadOnlyCollection<PathSegment>(result);
    }
}

internal sealed class SmoothingFixtureDocument
{
    [JsonProperty("schemaVersion")] public int SchemaVersion { get; set; }
    [JsonProperty("scenarios")] public List<SmoothingFixtureRecord> Scenarios { get; set; } = new List<SmoothingFixtureRecord>();
}

internal sealed class SmoothingFixtureRecord
{
    [JsonProperty("id")] public string Id { get; set; }
    [JsonProperty("fixtureVersion")] public int FixtureVersion { get; set; }
    [JsonProperty("configurationFingerprint")] public string ConfigurationFingerprint { get; set; }
    [JsonProperty("map")] public SmoothingFixtureMap Map { get; set; }
    [JsonProperty("vehicle")] public SmoothingFixtureVehicle Vehicle { get; set; }
    [JsonProperty("planningConfiguration")] public SmoothingFixturePlanningConfiguration PlanningConfiguration { get; set; }
    [JsonProperty("path")] public List<SmoothingFixturePathPoint> Path { get; set; } = new List<SmoothingFixturePathPoint>();
    [JsonProperty("segments")] public List<SmoothingFixtureSegment> Segments { get; set; } = new List<SmoothingFixtureSegment>();
}

internal sealed class SmoothingFixtureMap
{
    [JsonProperty("xMinMm")] public float XMinMm { get; set; }
    [JsonProperty("xMaxMm")] public float XMaxMm { get; set; }
    [JsonProperty("yMinMm")] public float YMinMm { get; set; }
    [JsonProperty("yMaxMm")] public float YMaxMm { get; set; }
    [JsonProperty("resolutionMm")] public float ResolutionMm { get; set; }
    [JsonProperty("obstacles")] public List<SmoothingFixtureObstacle> Obstacles { get; set; } = new List<SmoothingFixtureObstacle>();
}

internal sealed class SmoothingFixtureObstacle
{
    [JsonProperty("kind")] public string Kind { get; set; }
    [JsonProperty("xMinMm")] public float XMinMm { get; set; }
    [JsonProperty("xMaxMm")] public float XMaxMm { get; set; }
    [JsonProperty("yMinMm")] public float YMinMm { get; set; }
    [JsonProperty("yMaxMm")] public float YMaxMm { get; set; }
    [JsonProperty("centerXMm")] public float CenterXMm { get; set; }
    [JsonProperty("centerYMm")] public float CenterYMm { get; set; }
    [JsonProperty("radiusMm")] public float RadiusMm { get; set; }
}

internal sealed class SmoothingFixtureVehicle
{
    [JsonProperty("lengthMeters")] public double LengthMeters { get; set; }
    [JsonProperty("widthMeters")] public double WidthMeters { get; set; }
    [JsonProperty("safetyMarginMeters")] public double SafetyMarginMeters { get; set; }
    [JsonProperty("maximumCurvaturePerMeter")] public double MaximumCurvaturePerMeter { get; set; }
}

/// <summary>产生夹具粗路径时使用的 Hybrid A* 配置快照；仅用于溯源和指纹验证，不参与快速夹具加载时的规划。</summary>
internal sealed class SmoothingFixturePlanningConfiguration
{
    [JsonProperty("primitiveLengthMeters")] public double PrimitiveLengthMeters { get; set; }
    [JsonProperty("integrationStepMeters")] public double IntegrationStepMeters { get; set; }
    [JsonProperty("maximumCollisionCheckStepMeters")] public double MaximumCollisionCheckStepMeters { get; set; }
    [JsonProperty("headingResolutionRadians")] public double HeadingResolutionRadians { get; set; }
    [JsonProperty("curvatureLevelCount")] public int CurvatureLevelCount { get; set; }
    [JsonProperty("goalPositionToleranceMeters")] public double GoalPositionToleranceMeters { get; set; }
    [JsonProperty("goalHeadingToleranceRadians")] public double GoalHeadingToleranceRadians { get; set; }
    [JsonProperty("maximumExpandedNodes")] public int MaximumExpandedNodes { get; set; }
    [JsonProperty("searchTimeoutSeconds")] public double SearchTimeoutSeconds { get; set; }
    [JsonProperty("heuristicWeight")] public double HeuristicWeight { get; set; }
    [JsonProperty("reverseCostMultiplier")] public double ReverseCostMultiplier { get; set; }
    [JsonProperty("gearSwitchPenaltyMeters")] public double GearSwitchPenaltyMeters { get; set; }
    [JsonProperty("curvatureMagnitudeWeight")] public double CurvatureMagnitudeWeight { get; set; }
    [JsonProperty("curvatureChangePenaltyMetersPerLevel")] public double CurvatureChangePenaltyMetersPerLevel { get; set; }
    [JsonProperty("clearanceCostWeight")] public double ClearanceCostWeight { get; set; }
    [JsonProperty("clearanceCostDistanceMeters")] public double ClearanceCostDistanceMeters { get; set; }
    [JsonProperty("allowReverse")] public bool AllowReverse { get; set; }
}

internal sealed class SmoothingFixturePathPoint
{
    [JsonProperty("xMeters")] public double XMeters { get; set; }
    [JsonProperty("yMeters")] public double YMeters { get; set; }
    [JsonProperty("headingRadians")] public double HeadingRadians { get; set; }
    [JsonProperty("unwrappedHeadingRadians")] public double UnwrappedHeadingRadians { get; set; }
    [JsonProperty("arcLengthMeters")] public double ArcLengthMeters { get; set; }
    [JsonProperty("direction")] public TravelDirection Direction { get; set; }
    [JsonProperty("vehicleCurvaturePerMeter")] public double VehicleCurvaturePerMeter { get; set; }
    [JsonProperty("bodyClearanceMeters")] public double BodyClearanceMeters { get; set; }
    [JsonProperty("isGearSwitchPoint")] public bool IsGearSwitchPoint { get; set; }
    [JsonProperty("source")] public CoarsePathPointSource Source { get; set; }
}

internal sealed class SmoothingFixtureSegment
{
    [JsonProperty("segmentIndex")] public int SegmentIndex { get; set; }
    [JsonProperty("direction")] public TravelDirection Direction { get; set; }
    [JsonProperty("startIndex")] public int StartIndex { get; set; }
    [JsonProperty("endIndex")] public int EndIndex { get; set; }
    [JsonProperty("startsAtGearSwitch")] public bool StartsAtGearSwitch { get; set; }
    [JsonProperty("endsAtGearSwitch")] public bool EndsAtGearSwitch { get; set; }
}
