namespace ClawdDotNet.Core.Storage;

/// <summary>
/// Erzeugt Dateinamen, die auf Windows <b>und</b> Linux gültig sind.
///
/// Hintergrund (Linux-Portierung): <see cref="Path.GetInvalidFileNameChars"/> liefert
/// unter Windows 41 Zeichen, unter Unix genau zwei (<c>\0</c> und <c>/</c>). Wer sich
/// darauf verlässt, erzeugt unter Linux Namen wie <c>bericht:2026.zip</c> — dort
/// zulässig, unter Windows nicht anlegbar.
///
/// Das trifft alles, was zwischen Systemen wandert: Sicherungsarchive, Logdateien,
/// Task-Dateien im geteilten Arbeitsverzeichnis. Deshalb hier bewusst der strengere
/// Maßstab auf beiden Plattformen — ein paar Unterstriche mehr sind billiger als eine
/// Sicherung, die sich auf dem Zielsystem nicht auspacken lässt.
/// </summary>
public static class PortableFileName
{
    /// <summary>Unter Windows unzulässig, unter Unix erlaubt — hier immer ersetzt.</summary>
    private static readonly char[] WindowsReserved =
        ['<', '>', ':', '"', '/', '\\', '|', '?', '*'];

    /// <summary>
    /// Gerätenamen, die Windows unabhängig von der Endung nicht als Datei zulässt.
    /// Unter Linux völlig gewöhnliche Namen — deshalb fällt es dort erst beim
    /// Zurückspielen auf.
    /// </summary>
    private static readonly string[] ReservedNames =
    [
        "CON", "PRN", "AUX", "NUL",
        "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
        "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
    ];

    public static string Sanitize(string? name, string fallback = "unbenannt")
    {
        if (string.IsNullOrWhiteSpace(name))
            return fallback;

        var chars = name.Select(c =>
            c < 32 || WindowsReserved.Contains(c) ? '_' : c).ToArray();

        // Windows schneidet abschließende Punkte und Leerzeichen stillschweigend ab —
        // aus "bericht." würde "bericht", und zwei Dateien fielen zusammen.
        var result = new string(chars).TrimEnd('.', ' ');

        if (result.Length == 0)
            return fallback;

        var stem = Path.GetFileNameWithoutExtension(result);
        if (ReservedNames.Contains(stem, StringComparer.OrdinalIgnoreCase))
            result = "_" + result;

        return result;
    }
}
