using System;
using System.IO;

namespace MultiWheelC.TrajectoryPlanning.Mapping;

/// <summary>可选 PNG 导出器；它永远不参与地图构建、障碍物投影或缓存指纹计算。</summary>
public static class PlanningMapImageExporter
{
    /// <summary>每个规划栅格在输出图中占用的边长，单位为像素。</summary>
    public const int PixelsPerCell = 4;
    /// <summary>输出 PNG 单边允许的最大像素数，超过时拒绝导出。</summary>
    public const int MaximumImageEdgePixels = 4000;
    /// <summary>输出 PNG 允许的最大文件大小，单位为字节（50 MiB）。</summary>
    public const long MaximumFileSizeBytes = 50L * 1024L * 1024L;
    /// <summary>写入 PNG 的物理分辨率元数据，单位 DPI。</summary>
    public const float OutputDpi = 300f;
    private const int MaximumFilenameAttempts = 1024;

    /// <summary>
    /// 在开关开启时导出规划地图 PNG。
    ///
    /// 参数：enabled 为导出开关；request 包含不可变地图和输出根目录。
    /// 返回：开关关闭时返回 Skipped；成功时返回 Saved、路径、字节数与像素尺寸；输入或尺寸不合法时返回失败信息。
    /// 注意：该方法仅用于调试，绝不会影响地图创建和缓存结果。
    /// </summary>
    public static PlanningMapImageExportResult ExportIfEnabled(bool enabled, PlanningMapImageExportRequest request)
    {
        if (!enabled) return new PlanningMapImageExportResult { Skipped = true, Message = "Planning map image export is disabled." };
        if (request == null || request.Map == null) return Rejected("Planning map image export requires a PlanningGridMap.");
        if (string.IsNullOrWhiteSpace(request.OutputRootDirectory)) return Rejected("Planning map image export requires an output root directory.");
        long width = (long)request.Map.Cols * PixelsPerCell, height = (long)request.Map.Rows * PixelsPerCell;
        if (width <= 0 || height <= 0 || width > MaximumImageEdgePixels || height > MaximumImageEdgePixels) return Rejected("Planning map image dimensions exceed the permitted edge.", width, height);
        string temporary = null;
        try
        {
            string directory = Path.Combine(request.OutputRootDirectory, "PlanningMapExports");
            Directory.CreateDirectory(directory);
            using (FileStream stream = CreateTemporaryFile(directory, out string finalPath, out temporary))
            {
                byte[] rgba = PlanningMapImageRenderer.Render(request.Map, PixelsPerCell, out int pixelWidth, out int pixelHeight);
                ValidatedPngWriter.Write(rgba, pixelWidth, pixelHeight, stream);
            }
            long length = new FileInfo(temporary).Length;
            if (length > MaximumFileSizeBytes) return Rejected("Planning map image PNG exceeds 50 MiB.", width, height);
            string completed = temporary.Substring(0, temporary.Length - 4);
            File.Move(temporary, completed); temporary = null;
            return new PlanningMapImageExportResult { Saved = true, FilePath = completed, FileSizeBytes = length, PixelWidth = (int)width, PixelHeight = (int)height, Message = "Planning map image export saved." };
        }
        catch (Exception exception) { return Rejected("Planning map image export failed: " + exception.Message, width, height); }
        finally { if (temporary != null && File.Exists(temporary)) File.Delete(temporary); }
    }

    private static PlanningMapImageExportResult Rejected(string message, long width = 0, long height = 0) { return new PlanningMapImageExportResult { Message = message, PixelWidth = width > int.MaxValue ? int.MaxValue : (int)width, PixelHeight = height > int.MaxValue ? int.MaxValue : (int)height }; }
    private static FileStream CreateTemporaryFile(string directory, out string finalPath, out string temporaryPath)
    {
        string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss_fff");
        for (int index = 0; index < MaximumFilenameAttempts; index++)
        {
            string suffix = index == 0 ? string.Empty : "_" + index;
            finalPath = Path.Combine(directory, "PlanningMap_" + timestamp + suffix + ".png"); temporaryPath = finalPath + ".tmp";
            if (File.Exists(finalPath)) continue;
            try { return new FileStream(temporaryPath, FileMode.CreateNew, FileAccess.Write, FileShare.None); }
            catch (IOException) { }
        }
        finalPath = null; temporaryPath = null; throw new IOException("Could not reserve a unique PlanningMap PNG filename.");
    }
}
