using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging;

namespace AyaNova.Util
{
    public static class RunProgram
    {


        public static string Run(string cmd, string arguments, ILogger log = null, int waitForExitTimeOut = int.MaxValue)
        {
            try
            {
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    return RunWindows(cmd, arguments, waitForExitTimeOut);
                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    return RunOSX(cmd, arguments, waitForExitTimeOut);

                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    return RunLinuxShell(cmd, arguments, waitForExitTimeOut);
                }
            }
            catch (Exception ex)
            {
                if (log != null)
                {
                    log.LogError(ex, $"RunProgram error running command:{cmd} {arguments}");
                }
                throw;
            }




            throw new PlatformNotSupportedException();

        }



        private static string RunWindows(string cmd, string arguments, int waitForExitTimeOut = int.MaxValue)
        {
            //RunProgram.Run("cmd.exe",FullRunCommand, log);
            // var FullRunCommand=$"/C {BackupUtilityCommand} {Arguments}";

            //for Windows need to pass to cmd.exe because often have command line piping etc
            var args = $"/C {cmd} {arguments}";
            using (var process = new Process())
            {
                process.StartInfo = new ProcessStartInfo
                {
                    FileName = "cmd.exe",
                    Arguments = args,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                };


                process.Start();

                string result = $"{process.StandardOutput.ReadToEnd()}{process.StandardError.ReadToEnd()} ";
                if (!process.WaitForExit(waitForExitTimeOut))
                {
                    result += $"\nERROR: TIMED OUT {waitForExitTimeOut}ms BEFORE COMPLETION";
                }
                return result;
            }
        }

        private static string RunLinuxShell(string cmd, string arguments, int waitForExitTimeOut = int.MaxValue)
        {
            var escapedArgs = $"{cmd} {arguments}".Replace("\"", "\\\"");

            using (var process = new Process())
            {
                process.StartInfo = new ProcessStartInfo
                {
                    FileName = "/bin/sh",
                    Arguments = $"-c \"{escapedArgs}\"",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                };

                process.Start();
                string result = process.StandardOutput.ReadToEnd();
                if (!process.WaitForExit(waitForExitTimeOut))
                {
                    result += $"\nERROR: TIMED OUT {waitForExitTimeOut}ms BEFORE COMPLETION";
                }
                return result;
            }
        }


        private static string RunOSX(string cmd, string arguments, int waitForExitTimeOut = int.MaxValue)
        {
            using (var process = new Process())
            {
                process.StartInfo = new ProcessStartInfo
                {
                    FileName = cmd,
                    Arguments = arguments,
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                };

                process.Start();
                string result = process.StandardOutput.ReadToEnd();
                if (!process.WaitForExit(waitForExitTimeOut))
                {
                    result += $"\nERROR: TIMED OUT {waitForExitTimeOut}ms BEFORE COMPLETION";
                }
                return result;
            }
        }

    }
}