using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using UnityEngine;

namespace CommonUtil
{
    public class CmdResult
    {
        public int exitCode;
        // public string stdErr = "";
        // public string stdOut = "";

        public StringBuilder stdOut = new StringBuilder("");
        public StringBuilder stdErr = new StringBuilder("");
        public override string ToString()
        {
            return $"exitCode = {exitCode} \nstdErr = {{\n{stdErr}}}\nstdOut = {{\n{stdOut}}}";
        }

        public void Log(int max = 10000)
        {
            var sb = new StringBuilder();
            sb.Append($"exitCode = {exitCode} \nstdErr = {{\n{stdErr}}}\nstdOut = {{\n{stdOut}}}\n");
            //分多次打印，防止超出jenkins日志长度限制
            int count = sb.Length / max + 1;
            for (int i = 0; i < count; i++)
            {
                int start = i * max;
                int end = (i + 1) * max;
                if (end > sb.Length)
                {
                    end = sb.Length;
                }
                Console.Write(sb.ToString(start, end - start));
            }
        }
    }
    public class CmdUtil
    {
        public static CmdResult Cmd(string command, string args, string workPath = "", bool isPrint = false, Dictionary<string, string> envs = null)
        {
            //UnityEngine.Debug.Log($"[DEBG] cmd {command} {args}");//waste too much time logging
            Process p = new Process();
            p.StartInfo.FileName = command;
            p.StartInfo.UseShellExecute = false;                    //这里是关键点,不用Shell启动
            p.StartInfo.RedirectStandardInput = true;               //重定向输入
            p.StartInfo.RedirectStandardOutput = true;              //重定向输出
            p.StartInfo.RedirectStandardError = true;               //重定向标准错误输出
            p.StartInfo.StandardOutputEncoding = Encoding.UTF8;
            p.StartInfo.StandardErrorEncoding = Encoding.UTF8;
            p.StartInfo.CreateNoWindow = true;                      //不显示窗口
            p.StartInfo.Arguments = args;
            if (workPath != "")
            {
                p.StartInfo.WorkingDirectory = workPath;
            }
            if (envs != null)
            {
                foreach (string key in envs.Keys)
                {
                    if (p.StartInfo.EnvironmentVariables.ContainsKey(key))
                    {
                        p.StartInfo.EnvironmentVariables[key] = envs[key];
                    }
                    else
                    {
                        p.StartInfo.EnvironmentVariables.Add(key, envs[key]);
                    }
                }
            }

            var result = new CmdResult();
            p.ErrorDataReceived += new DataReceivedEventHandler((sender, e) =>
            {
                if (string.IsNullOrEmpty(e.Data))
                    return;
                result.stdErr.Append(e.Data).Append("\n");
                if (isPrint)
                {
                    UnityEngine.Debug.Log("[INFO] [stdErr] " + e.Data);
                }
                // result.stdErr += e.Data + "\n";
            });
            p.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
            {
                if (string.IsNullOrEmpty(e.Data))
                    return;
                result.stdOut.Append(e.Data).Append("\n");
                if (isPrint)
                {
                    UnityEngine.Debug.Log("[INFO] [stdOut] " + e.Data + " count:" + result.stdOut.Length);
                }
                // result.stdOut += e.Data + "\n";
            });
            p.Start();
            p.BeginErrorReadLine();
            p.BeginOutputReadLine();
            p.WaitForExit();
            result.exitCode = p.ExitCode;
            p.Close();
            if (isPrint && result.exitCode != 0)
            {
                UnityEngine.Debug.Log($"[ERRO] {result}");
            }
            return result;
        }

        //sometimes very slow,deprecated
        //public static void RunFuncsAsync(List<Action> funcs, int multi = 1, Action<int, int> progress = null)
        //{
        //    int taskMax = SystemInfo.processorCount * multi;
        //    UnityEngine.Debug.Log($"最大任务数{taskMax}");
        //    TaskFactory fac = new TaskFactory(new LimitedConcurrencyLevelTaskScheduler(taskMax));
        //    List<Task> tasks = new List<Task>();
        //    foreach (Action f in funcs)
        //    {
        //        Task task = fac.StartNew(f);
        //        tasks.Add(task);
        //    }
        //    if (progress == null)
        //    {
        //        Task.WaitAll(tasks.ToArray());
        //    }
        //    else
        //    {
        //        Task whenAllTask = Task.WhenAll(tasks);
        //        while (!whenAllTask.IsCompleted)
        //        {
        //            Thread.Sleep(500);
        //            int finishedCount = tasks.Count(task => task.IsCompleted);
        //            progress?.Invoke(finishedCount, tasks.Count);
        //        }
        //    }
        //}
    }
}
