using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using TrajectoryPlanningVisualization;

namespace TrajectoryPlanningVisualizationVerificationHost;

internal static class ContractChecks
{
    public static void Run()
    {
        CopiesCollectionsAndRejectsNonFiniteNumbers();
        StoresOccupancyAsDefensiveCompactBits();
        ExposesImmutableSnapshotContracts();
        ExposesChartAnnotationContract();
        DocumentsPublicSafetyAndLifecycleBoundary();
    }

    private static void CopiesCollectionsAndRejectsNonFiniteNumbers()
    {
        var points = new List<VisualizationPoint> { new VisualizationPoint(1d, 2d) };
        var series = new VisualizationSeries("current", "当前轨迹", VisualizationLineStyle.Solid, points);
        points[0] = new VisualizationPoint(9d, 9d);

        Verification.NearlyEqual(1d, series.Points[0].X, "series copies points");
        Verification.Throws<ArgumentOutOfRangeException>(
            () => new VisualizationPoint(double.NaN, 0d), "point rejects NaN");
        Verification.Throws<ArgumentOutOfRangeException>(
            () => new VisualizationPose(0d, 0d, double.PositiveInfinity), "pose rejects infinity");
        Verification.Throws<ArgumentOutOfRangeException>(
            () => new VisualizationBounds(0d, 1d, 0d, double.NaN), "bounds rejects NaN");
        Verification.Throws<ArgumentException>(
            () => new VisualizationSeries("invalid", "无效", VisualizationLineStyle.Solid,
                new VisualizationPoint[] { null! }), "series rejects null point");
    }

    private static void StoresOccupancyAsDefensiveCompactBits()
    {
        byte[] bits = { 0x01 };
        var grid = new VisualizationOccupancyGrid(new VisualizationBounds(0d, 1d, 0d, 1d),
            0.5d, rows: 2, columns: 2, bits);
        bits[0] = 0x00;

        Verification.Equal("AQ==", grid.OccupancyBitsBase64, "occupancy grid copies compact bits");
        Verification.Throws<ArgumentException>(
            () => new VisualizationOccupancyGrid(new VisualizationBounds(0d, 1d, 0d, 1d),
                0.5d, rows: 2, columns: 2, new byte[2]), "occupancy grid validates bit length");
    }

    private static void ExposesImmutableSnapshotContracts()
    {
        var staticSnapshot = new PlanningVisualizationStaticSnapshot(
            "会话",
            new VisualizationBounds(0d, 1d, 0d, 1d),
            null,
            Array.Empty<VisualizationPolyline>(),
            Array.Empty<VisualizationMarker>(),
            Array.Empty<VisualizationDirectionSegment>(),
            Array.Empty<VisualizationConfigurationGroup>());
        var dynamicSnapshot = new PlanningVisualizationDynamicSnapshot(
            1L,
            DateTimeOffset.UtcNow,
            "运行中",
            0,
            "forward",
            new VisualizationPose(0d, 0d, 0d),
            Array.Empty<VisualizationPolyline>(),
            Array.Empty<VisualizationMarker>(),
            Array.Empty<VisualizationChart>(),
            Array.Empty<VisualizationValue>(),
            new VisualizationCycleSummary(1L, DateTimeOffset.UtcNow, "成功", true, 1d, 0,
                "forward", "rolling", "none", null, null, ""));

        Verification.True(staticSnapshot.StaticPolylines.GetType().Name.Contains("ReadOnlyCollection"),
            "static snapshot uses read-only collection");
        Verification.True(dynamicSnapshot.Charts.GetType().Name.Contains("ReadOnlyCollection"),
            "dynamic snapshot uses read-only collection");
        AssertNoSetters(typeof(PlanningVisualizationStaticSnapshot));
        AssertNoSetters(typeof(PlanningVisualizationDynamicSnapshot));
    }

    private static void AssertNoSetters(Type type)
    {
        foreach (PropertyInfo property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            Verification.True(property.SetMethod == null, type.Name + " exposes no property setters");
        }
    }

    private static void ExposesChartAnnotationContract()
    {
        Type chartType = typeof(VisualizationChart);
        PropertyInfo annotationsProperty = chartType.GetProperty("Annotations");
        Verification.True(annotationsProperty != null, "chart exposes immutable annotations");
        Type annotationType = chartType.Assembly.GetType("TrajectoryPlanningVisualization.VisualizationChartAnnotation");
        Verification.True(annotationType != null, "chart annotation contract type exists");

        var chart = new VisualizationChart("annotation-legacy", "标题", "x (m)", "y (m)",
            new[]
            {
                new VisualizationSeries("s", "轨迹", VisualizationLineStyle.Solid,
                    new[] { new VisualizationPoint(0d, 0d) })
            });
        if (annotationsProperty == null)
        {
            return;
        }

        object value = annotationsProperty.GetValue(chart);
        Verification.True(value is System.Collections.IEnumerable, "chart annotations are enumerable");
        int count = 0;
        foreach (object annotation in (System.Collections.IEnumerable)value)
        {
            count++;
        }
        Verification.Equal(0, count, "legacy chart constructor keeps annotations empty");
        AssertNoSetters(chartType);
    }

    private static void DocumentsPublicSafetyAndLifecycleBoundary()
    {
        string readmePath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory,
            "..", "..", "..", "..", "..", "TrajectoryPlanningVisualization", "README.md"));
        string readme = File.ReadAllText(readmePath);

        Verification.True(readme.Contains("OBSERVE_ONLY"), "README documents observe-only boundary");
        Verification.True(readme.Contains("127.0.0.1"), "README documents loopback boundary");
        Verification.True(readme.Contains("capacity 1"), "README documents latest-frame capacity");
        Verification.True(readme.Contains("60"), "README documents default history limit");
        Verification.True(readme.Contains("10 Hz"), "README documents default refresh rate");
        Verification.True(readme.Contains("j[i]"), "README documents jerk interval semantics");
        Verification.True(readme.Contains("末点后无时间区间"), "README documents jerk terminal explanation");
        Verification.True(readme.Contains("PlanningVisualizationSessionInfo info = visualization.Start(staticSnapshot);"),
            "README documents Start example");
        Verification.True(readme.Contains("visualization.Publish(dynamicSnapshot);"), "README documents Publish example");
        Verification.True(readme.Contains("visualization.Stop();"), "README documents Stop example");
    }
}
