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

namespace AxCopilot.Services.Agent;

public class GrepTool : IAgentTool
{
	public string Name => "grep";

	public string Description => "Search file contents for a pattern (regex supported). Returns matching lines with file paths and line numbers.";

	public ToolParameterSchema Parameters
	{
		get
		{
			ToolParameterSchema obj = new ToolParameterSchema
			{
				Properties = new Dictionary<string, ToolProperty>
				{
					["pattern"] = new ToolProperty
					{
						Type = "string",
						Description = "Search pattern (regex supported)"
					},
					["path"] = new ToolProperty
					{
						Type = "string",
						Description = "File or directory to search in. Optional, defaults to work folder."
					},
					["glob"] = new ToolProperty
					{
						Type = "string",
						Description = "File pattern filter (e.g. '*.cs', '*.json'). Optional."
					},
					["context_lines"] = new ToolProperty
					{
						Type = "integer",
						Description = "Number of context lines before/after each match (0-5). Default 0."
					},
					["case_sensitive"] = new ToolProperty
					{
						Type = "boolean",
						Description = "Case-sensitive search. Default false (case-insensitive)."
					}
				}
			};
			int num = 1;
			List<string> list = new List<string>(num);
			CollectionsMarshal.SetCount(list, num);
			CollectionsMarshal.AsSpan(list)[0] = "pattern";
			obj.Required = list;
			return obj;
		}
	}

	public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
	{
		string text = args.GetProperty("pattern").GetString() ?? "";
		JsonElement value;
		string text2 = (args.TryGetProperty("path", out value) ? (value.GetString() ?? "") : "");
		JsonElement value2;
		string text3 = (args.TryGetProperty("glob", out value2) ? (value2.GetString() ?? "") : "");
		JsonElement value3;
		int num = (args.TryGetProperty("context_lines", out value3) ? Math.Clamp(value3.GetInt32(), 0, 5) : 0);
		JsonElement value4;
		bool flag = args.TryGetProperty("case_sensitive", out value4) && value4.GetBoolean();
		string text4 = (string.IsNullOrEmpty(text2) ? context.WorkFolder : FileReadTool.ResolvePath(text2, context.WorkFolder));
		if (string.IsNullOrEmpty(text4))
		{
			return Task.FromResult(ToolResult.Fail("작업 폴더가 설정되지 않았습니다."));
		}
		try
		{
			RegexOptions options = (RegexOptions)(8 | ((!flag) ? 1 : 0));
			Regex regex = new Regex(text, options, TimeSpan.FromSeconds(5.0));
			string searchPattern = (string.IsNullOrEmpty(text3) ? "*" : text3);
			IEnumerable<string> enumerable;
			if (File.Exists(text4))
			{
				enumerable = new _003C_003Ez__ReadOnlySingleElementList<string>(text4);
			}
			else
			{
				if (!Directory.Exists(text4))
				{
					return Task.FromResult(ToolResult.Fail("경로가 존재하지 않습니다: " + text4));
				}
				enumerable = Directory.EnumerateFiles(text4, searchPattern, SearchOption.AllDirectories);
			}
			StringBuilder stringBuilder = new StringBuilder();
			int num2 = 0;
			int num3 = 0;
			foreach (string item in enumerable)
			{
				if (ct.IsCancellationRequested)
				{
					break;
				}
				if (!context.IsPathAllowed(item) || IsBinaryFile(item))
				{
					continue;
				}
				try
				{
					string[] array = File.ReadAllLines(item, Encoding.UTF8);
					bool flag2 = false;
					for (int i = 0; i < array.Length; i++)
					{
						if (num2 >= 100)
						{
							break;
						}
						if (!regex.IsMatch(array[i]))
						{
							continue;
						}
						StringBuilder stringBuilder2;
						StringBuilder.AppendInterpolatedStringHandler handler;
						if (!flag2)
						{
							string value5 = (Directory.Exists(context.WorkFolder) ? Path.GetRelativePath(context.WorkFolder, item) : item);
							stringBuilder2 = stringBuilder;
							StringBuilder stringBuilder3 = stringBuilder2;
							handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
							handler.AppendLiteral("\n");
							handler.AppendFormatted(value5);
							handler.AppendLiteral(":");
							stringBuilder3.AppendLine(ref handler);
							flag2 = true;
							num3++;
						}
						if (num > 0)
						{
							for (int j = Math.Max(0, i - num); j < i; j++)
							{
								stringBuilder2 = stringBuilder;
								StringBuilder stringBuilder4 = stringBuilder2;
								handler = new StringBuilder.AppendInterpolatedStringHandler(4, 2, stringBuilder2);
								handler.AppendLiteral("  ");
								handler.AppendFormatted(j + 1);
								handler.AppendLiteral("  ");
								handler.AppendFormatted(array[j].TrimEnd());
								stringBuilder4.AppendLine(ref handler);
							}
						}
						stringBuilder2 = stringBuilder;
						StringBuilder stringBuilder5 = stringBuilder2;
						handler = new StringBuilder.AppendInterpolatedStringHandler(4, 2, stringBuilder2);
						handler.AppendLiteral("  ");
						handler.AppendFormatted(i + 1);
						handler.AppendLiteral(": ");
						handler.AppendFormatted(array[i].TrimEnd());
						stringBuilder5.AppendLine(ref handler);
						if (num > 0)
						{
							for (int k = i + 1; k <= Math.Min(array.Length - 1, i + num); k++)
							{
								stringBuilder2 = stringBuilder;
								StringBuilder stringBuilder6 = stringBuilder2;
								handler = new StringBuilder.AppendInterpolatedStringHandler(4, 2, stringBuilder2);
								handler.AppendLiteral("  ");
								handler.AppendFormatted(k + 1);
								handler.AppendLiteral("  ");
								handler.AppendFormatted(array[k].TrimEnd());
								stringBuilder6.AppendLine(ref handler);
							}
							stringBuilder.AppendLine("  ---");
						}
						num2++;
					}
				}
				catch
				{
				}
				if (num2 < 100)
				{
					continue;
				}
				break;
			}
			if (num2 == 0)
			{
				return Task.FromResult(ToolResult.Ok("패턴 '" + text + "'에 일치하는 결과가 없습니다."));
			}
			string text5 = $"{num3}개 파일에서 {num2}개 일치{((num2 >= 100) ? " (제한 도달)" : "")}:";
			return Task.FromResult(ToolResult.Ok(text5 + stringBuilder));
		}
		catch (RegexParseException)
		{
			return Task.FromResult(ToolResult.Fail("잘못된 정규식 패턴: " + text));
		}
		catch (Exception ex2)
		{
			return Task.FromResult(ToolResult.Fail("검색 실패: " + ex2.Message));
		}
	}

	private static bool IsBinaryFile(string path)
	{
		switch (Path.GetExtension(path).ToLowerInvariant())
		{
		case ".exe":
		case ".dll":
		case ".zip":
		case ".7z":
		case ".rar":
		case ".tar":
		case ".gz":
		case ".png":
		case ".jpg":
		case ".jpeg":
		case ".gif":
		case ".bmp":
		case ".ico":
		case ".webp":
		case ".pdf":
		case ".docx":
		case ".xlsx":
		case ".pptx":
		case ".mp3":
		case ".mp4":
		case ".avi":
		case ".mov":
		case ".mkv":
		case ".psd":
		case ".msi":
		case ".iso":
		case ".bin":
		case ".dat":
		case ".db":
			return true;
		default:
			return false;
		}
	}
}
