// Copyright 2023-2024 Gentoo Authors
// Distributed under the terms of the GNU General Public License v2

namespace Gdmt.Shared

open System
open System.Diagnostics

open Gdmt.Shared.Types

/// <summary>
/// Execute a process, given args list.
/// </summary>
/// <remarks>
/// Execution returns itself.
/// Access exit code with the ExitCode field
/// and if the execution succeeded with the Success field.
/// </remarks>
/// <example>
/// <code>
/// ExecProcess(["ls"; "/"]).Run().Success;;
/// </code>
/// </example>
type ExecProcess(args: StringList, ?environmentMap: ProcessEnvironmentMap) =
    let _environmentMap = defaultArg environmentMap []

    let mutable _exitCode: Option<int> = None

    member this.RunCommand = args |> String.concat " "

    member this.ExitCode =
        match _exitCode with
        | Some(exitCode) -> exitCode
        | _ -> "process was not ran" |> Exception |> raise

    member this.Success = this.ExitCode = 0

    member this.Check() =
        if not this.Success then
            $"process failed, ran: {this.RunCommand}" |> Exception |> raise

    member this.Run() =
        let commandProcessStartInfo =
            let argsString = this.RunCommand |> sprintf "-c \"%s\""

            new ProcessStartInfo("/bin/sh", argsString)

        for (envMapKey, envMapValue) in _environmentMap do
            commandProcessStartInfo.Environment.[envMapKey] <- envMapValue

        commandProcessStartInfo.RedirectStandardOutput <- false
        commandProcessStartInfo.UseShellExecute <- false
        commandProcessStartInfo.CreateNoWindow <- true

        use commandProcess = new Process()
        commandProcess.StartInfo <- commandProcessStartInfo
        commandProcess.Start() |> ignore

        commandProcess.WaitForExit()

        _exitCode <- Some(commandProcess.ExitCode)

        this
