using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace AxCopilot.Services.Agent;

public class ProcessTool : IAgentTool
{
	private static readonly string[] DangerousPatterns = new string[16]
	{
		"format ", "del /s", "rd /s", "rmdir /s", "rm -rf", "Remove-Item -Recurse -Force", "Stop-Computer", "Restart-Computer", "shutdown", "taskkill /f",
		"reg delete", "reg add", "net user", "net localgroup", "schtasks /create", "schtasks /delete"
	};

	public string Name => "process";

	public string Description => "Execute a shell command (cmd or powershell). Returns stdout and stderr. Has a timeout limit.";

	public ToolParameterSchema Parameters
	{
		get
		{
			ToolParameterSchema toolParameterSchema = new ToolParameterSchema();
			Dictionary<string, ToolProperty> obj = new Dictionary<string, ToolProperty> { ["command"] = new ToolProperty
			{
				Type = "string",
				Description = "Command to execute"
			} };
			ToolProperty obj2 = new ToolProperty
			{
				Type = "string",
				Description = "Shell to use: 'cmd' or 'powershell'. Default: 'cmd'."
			};
			int num = 2;
			List<string> list = new List<string>(num);
			CollectionsMarshal.SetCount(list, num);
			Span<string> span = CollectionsMarshal.AsSpan(list);
			span[0] = "cmd";
			span[1] = "powershell";
			obj2.Enum = list;
			obj["shell"] = obj2;
			obj["timeout"] = new ToolProperty
			{
				Type = "integer",
				Description = "Timeout in seconds. Default: 30, max: 120."
			};
			toolParameterSchema.Properties = obj;
			num = 1;
			List<string> list2 = new List<string>(num);
			CollectionsMarshal.SetCount(list2, num);
			CollectionsMarshal.AsSpan(list2)[0] = "command";
			toolParameterSchema.Required = list2;
			return toolParameterSchema;
		}
	}

	public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
	{
		if (!args.TryGetProperty("command", out var cmdEl))
		{
			return ToolResult.Fail("command가 필요합니다.");
		}
		string command = cmdEl.GetString() ?? "";
		JsonElement sh;
		string shell = (args.TryGetProperty("shell", out sh) ? (sh.GetString() ?? "cmd") : "cmd");
		JsonElement to;
		int timeout = (args.TryGetProperty("timeout", out to) ? Math.Min(to.GetInt32(), 120) : 30);
		if (string.IsNullOrWhiteSpace(command))
		{
			return ToolResult.Fail("명령이 비어 있습니다.");
		}
		string[] dangerousPatterns = DangerousPatterns;
		foreach (string pattern in dangerousPatterns)
		{
			if (command.Contains(pattern, StringComparison.OrdinalIgnoreCase))
			{
				return ToolResult.Fail("위험 명령 차단: '" + pattern + "' 패턴이 감지되었습니다.");
			}
		}
		if (!(await context.CheckWritePermissionAsync(Name, command)))
		{
			return ToolResult.Fail("명령 실행 권한 거부");
		}
		try
		{
			string arguments;
			string fileName;
			if (!(shell == "powershell"))
			{
				string text = "/C " + command;
				arguments = text;
				fileName = "cmd.exe";
			}
			else
			{
				string text = "-NoProfile -NonInteractive -Command \"" + command.Replace("\"", "\\\"") + "\"";
				arguments = text;
				fileName = "powershell.exe";
			}
			ProcessStartInfo psi = new ProcessStartInfo
			{
				FileName = fileName,
				Arguments = arguments,
				UseShellExecute = false,
				RedirectStandardOutput = true,
				RedirectStandardError = true,
				CreateNoWindow = true,
				StandardOutputEncoding = Encoding.UTF8,
				StandardErrorEncoding = Encoding.UTF8
			};
			if (!string.IsNullOrEmpty(context.WorkFolder) && Directory.Exists(context.WorkFolder))
			{
				psi.WorkingDirectory = context.WorkFolder;
			}
			using Process process = new Process
			{
				StartInfo = psi
			};
			StringBuilder stdout = new StringBuilder();
			StringBuilder stderr = new StringBuilder();
			process.OutputDataReceived += delegate(object _, DataReceivedEventArgs e)
			{
				if (e.Data != null)
				{
					stdout.AppendLine(e.Data);
				}
			};
			process.ErrorDataReceived += delegate(object _, DataReceivedEventArgs e)
			{
				if (e.Data != null)
				{
					stderr.AppendLine(e.Data);
				}
			};
			process.Start();
			process.BeginOutputReadLine();
			process.BeginErrorReadLine();
			using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
			cts.CancelAfter(TimeSpan.FromSeconds(timeout));
			try
			{
				await process.WaitForExitAsync(cts.Token);
			}
			catch (OperationCanceledException)
			{
				try
				{
					process.Kill(entireProcessTree: true);
				}
				catch
				{
				}
				return ToolResult.Fail($"명령 실행 타임아웃 ({timeout}초 초과)");
			}
			string output = stdout.ToString().TrimEnd();
			string error = stderr.ToString().TrimEnd();
			if (output.Length > 8000)
			{
				output = output.Substring(0, 8000) + "\n... (출력 잘림)";
			}
			StringBuilder result = new StringBuilder();
			StringBuilder stringBuilder = result;
			StringBuilder stringBuilder2 = stringBuilder;
			StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder);
			handler.AppendLiteral("[Exit code: ");
			handler.AppendFormatted(process.ExitCode);
			handler.AppendLiteral("]");
			stringBuilder2.AppendLine(ref handler);
			if (!string.IsNullOrEmpty(output))
			{
				result.AppendLine(output);
			}
			if (!string.IsNullOrEmpty(error))
			{
				stringBuilder = result;
				StringBuilder stringBuilder3 = stringBuilder;
				handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder);
				handler.AppendLiteral("[stderr]\n");
				handler.AppendFormatted(error);
				stringBuilder3.AppendLine(ref handler);
			}
			return (process.ExitCode == 0) ? ToolResult.Ok(result.ToString()) : ToolResult.Ok(result.ToString());
		}
		catch (Exception ex2)
		{
			return ToolResult.Fail("명령 실행 실패: " + ex2.Message);
		}
	}
}
