using System.Diagnostics;
using Metin2Launcher.Logging;
using Metin2Launcher.Runtime;

namespace Metin2Launcher.GameLaunch;

/// <summary>
/// Starts the Metin2 game executable and detaches.
///
/// On Windows (or when the launcher itself runs under Wine) the game is a native
/// child of the parent process, so <see cref="Process.Start(ProcessStartInfo)"/>
/// is enough. On Linux-native dev/test runs the executable is a PE binary that
/// cannot be invoked directly; we must spawn <c>wine</c> explicitly so the child
/// inherits the caller's <c>WINEPREFIX</c>. Without this, binfmt_misc would fall
/// back to the default <c>~/.wine</c> prefix, which does not have Tahoma / d3dx9 /
/// vcrun2022 installed and produces a broken client (invisible fonts, missing
/// DLLs).
/// </summary>
public static class GameProcess
{
    public static bool Launch(string clientRoot, string executableName, RuntimeKey? runtimeKey = null)
    {
        var exePath = Path.Combine(clientRoot, executableName);
        if (!File.Exists(exePath))
        {
            Log.Error($"game executable not found at {exePath}");
            return false;
        }

        try
        {
            var psi = BuildStartInfo(exePath, clientRoot, runtimeKey);
            var p = Process.Start(psi);
            if (p is null)
            {
                Log.Error("Process.Start returned null");
                return false;
            }
            Log.Info($"launched {executableName} pid={p.Id}");
            return true;
        }
        catch (Exception ex)
        {
            Log.Error($"failed to launch {executableName}", ex);
            return false;
        }
    }

    /// <summary>
    /// Builds the <see cref="ProcessStartInfo"/> for the game executable, taking
    /// into account whether the caller is a native Linux process (which must go
    /// through <c>wine</c>) or is itself a Windows binary (which can exec directly).
    /// Public so tests can assert the platform branch without actually launching.
    /// </summary>
    public static ProcessStartInfo BuildStartInfo(
        string exePath,
        string workingDirectory,
        RuntimeKey? runtimeKey = null)
    {
        ProcessStartInfo psi;
        if (OperatingSystem.IsLinux())
        {
            psi = new ProcessStartInfo
            {
                FileName = "wine",
                WorkingDirectory = workingDirectory,
                UseShellExecute = false,
            };
            psi.ArgumentList.Add(exePath);
            // The default ~/.wine prefix lacks tahoma + d3dx9 + vcrun, which
            // makes the client run with invisible fonts and missing renderer
            // DLLs. If the caller already set WINEPREFIX, honor it; otherwise
            // fall back to the metin-specific prefix prepared by
            // m2dev-client/scripts/setup-wine-prefix.sh.
            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WINEPREFIX")))
            {
                var home = Environment.GetEnvironmentVariable("HOME");
                if (!string.IsNullOrEmpty(home))
                {
                    var metinPrefix = Path.Combine(home, "metin", "wine-metin");
                    if (Directory.Exists(metinPrefix))
                        psi.Environment["WINEPREFIX"] = metinPrefix;
                }
            }
        }
        else
        {
            psi = new ProcessStartInfo
            {
                FileName = exePath,
                WorkingDirectory = workingDirectory,
                UseShellExecute = false,
            };
        }

        // Forward the m2pack runtime key via env vars scoped to the child.
        // MVP uses env var delivery only; the shared-memory delivery is stubbed
        // behind IRuntimeKeyDelivery and wired in later.
        if (runtimeKey is not null)
        {
            var delivery = new EnvVarKeyDelivery();
            delivery.Apply(psi, runtimeKey);
        }

        return psi;
    }
}
