using System.Diagnostics;

namespace ClawdDotNet.Core.Storage;

/// <summary>
/// Öffnet Ordner und Dateien im Dateimanager des Systems.
///
/// Hintergrund (Linux-Portierung): Die Oberfläche rief an vier Stellen direkt
/// <c>explorer.exe</c> auf. Hier liegt das plattformneutral — und in Core statt in der
/// Oberfläche, weil die künftige Avalonia-Fassung dieselben Aufrufe braucht.
///
/// Bewusst ohne Rückmeldung im Fehlerfall: Einen Ordner zu öffnen ist eine
/// Bequemlichkeit. Schlägt es fehl (kein Dateimanager installiert, Dienst ohne
/// Sitzung), soll das den Aufrufer nicht beschäftigen.
/// </summary>
public static class SystemShell
{
    /// <summary>Öffnet ein Verzeichnis im Dateimanager.</summary>
    public static bool OpenFolder(string path)
    {
        if (string.IsNullOrWhiteSpace(path) || !Directory.Exists(path))
            return false;

        return Open(path);
    }

    /// <summary>
    /// Öffnet den Ordner einer Datei und hebt sie nach Möglichkeit hervor.
    ///
    /// Das Hervorheben können nur Windows und macOS. Unter Linux gibt es keinen
    /// Aufruf, der über alle Dateimanager hinweg funktioniert — dort wird nur der
    /// Ordner geöffnet. Das ist der kleinere Verlust gegenüber einer Liste von
    /// Sonderfällen je Desktop-Umgebung.
    /// </summary>
    public static bool RevealFile(string path)
    {
        if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
            return false;

        var folder = Path.GetDirectoryName(Path.GetFullPath(path));
        if (string.IsNullOrEmpty(folder)) return false;

        try
        {
            if (OperatingSystem.IsWindows())
                return Start("explorer.exe", ["/select,", Path.GetFullPath(path)]);

            if (OperatingSystem.IsMacOS())
                return Start("open", ["-R", Path.GetFullPath(path)]);
        }
        catch { /* siehe Klassenkommentar */ }

        return OpenFolder(folder);
    }

    private static bool Open(string target)
    {
        var full = Path.GetFullPath(target);

        try
        {
            if (OperatingSystem.IsLinux())
                return Start("xdg-open", [full]);

            if (OperatingSystem.IsMacOS())
                return Start("open", [full]);

            // Windows: UseShellExecute lässt die Shell entscheiden, statt explorer.exe
            // festzuschreiben.
            using var process = Process.Start(new ProcessStartInfo(full)
            {
                UseShellExecute = true
            });
            return process is not null;
        }
        catch (Exception ex) when (ex is System.ComponentModel.Win32Exception or InvalidOperationException)
        {
            return false;
        }
    }

    /// <summary>
    /// Startet mit <c>ArgumentList</c> statt einer Argumentzeichenkette — so muss nichts
    /// maskiert werden, und ein Pfad mit Leerzeichen oder Anführungszeichen kann keinen
    /// zusätzlichen Aufruf einschleusen.
    /// </summary>
    private static bool Start(string fileName, string[] arguments)
    {
        var info = new ProcessStartInfo(fileName)
        {
            UseShellExecute = false,
            CreateNoWindow = true
        };

        foreach (var argument in arguments)
            info.ArgumentList.Add(argument);

        using var process = Process.Start(info);
        return process is not null;
    }
}
