using System;
using System.Globalization;
using System.Text;

namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.Output.Visualization;

/// <summary>把共享图形模型的指标表写为带 BOM 的 UTF-8 CSV。</summary>
public sealed class SmoothingCsvWriter
{
    private const string Header = "ScenarioId,Method,Status,PathLengthMeters,MaximumAbsoluteVehicleCurvaturePerMeter,RootMeanSquareVehicleCurvaturePerMeter,TotalAbsoluteCurvatureVariationPerMeter,CurvatureVariationEnergy,MinimumBodyClearanceMeters,MedianElapsedMilliseconds,TimingSampleCount,IsDeterministic";

    public byte[] Write(SmoothingFigureModel model)
    {
        if (model == null) throw new ArgumentNullException(nameof(model));
        var text = new StringBuilder(Header).Append("\r\n");
        for (int index = 0; index < model.MetricRows.Count; index++)
        {
            SmoothingFigureMetricRow row = model.MetricRows[index];
            PathQualityMetrics metrics = row.Metrics;
            text.Append(Field(model.ScenarioId)).Append(',').Append(Field(row.Method)).Append(',').Append(Field(row.Status.ToString())).Append(',')
                .Append(Number(metrics.PathLengthMeters)).Append(',').Append(Number(metrics.MaximumAbsoluteVehicleCurvaturePerMeter)).Append(',')
                .Append(Number(metrics.RootMeanSquareVehicleCurvaturePerMeter)).Append(',').Append(Number(metrics.TotalAbsoluteCurvatureVariationPerMeter)).Append(',')
                .Append(Number(metrics.CurvatureVariationEnergy)).Append(',').Append(Number(metrics.MinimumBodyClearanceMeters)).Append(',')
                .Append(Number(row.Timing == null ? 0d : row.Timing.MedianElapsedMilliseconds)).Append(',')
                .Append(row.Timing == null ? 0 : row.Timing.MeasuredElapsedMilliseconds.Count).Append(',')
                .Append(row.Timing != null && row.Timing.IsDeterministic ? "true" : "false").Append("\r\n");
        }
        byte[] body = new UTF8Encoding(false).GetBytes(text.ToString());
        byte[] preamble = new UTF8Encoding(true).GetPreamble();
        var output = new byte[preamble.Length + body.Length];
        Buffer.BlockCopy(preamble, 0, output, 0, preamble.Length);
        Buffer.BlockCopy(body, 0, output, preamble.Length, body.Length);
        return output;
    }

    private static string Number(double value) { return value.ToString("0.#################", CultureInfo.InvariantCulture); }
    private static string Field(string value)
    {
        string text = value ?? string.Empty;
        return text.IndexOfAny(new[] { ',', '\"', '\r', '\n' }) < 0 ? text : "\"" + text.Replace("\"", "\"\"") + "\"";
    }
}
