using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace AxCopilot.Services.Agent;

public class FolderMapTool : IAgentTool
{
	private static readonly HashSet<string> IgnoredDirs = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
	{
		"bin", "obj", "node_modules", ".git", ".vs", ".idea", ".vscode", "__pycache__", ".mypy_cache", ".pytest_cache",
		"dist", "build", "packages", ".nuget", "TestResults", "coverage", ".next", "target", ".gradle", ".cargo"
	};

	private const int MaxEntries = 500;

	public string Name => "folder_map";

	public string Description => "Generate a directory tree map of the work folder or a specified subfolder. Shows folders and files in a tree structure. Use this to understand the project layout before reading or editing files.";

	public ToolParameterSchema Parameters => new ToolParameterSchema
	{
		Properties = new Dictionary<string, ToolProperty>
		{
			["path"] = new ToolProperty
			{
				Type = "string",
				Description = "Subdirectory to map. Optional, defaults to work folder root."
			},
			["depth"] = new ToolProperty
			{
				Type = "integer",
				Description = "Maximum depth to traverse (1-10). Default: 3."
			},
			["include_files"] = new ToolProperty
			{
				Type = "boolean",
				Description = "Whether to include files. Default: true."
			},
			["pattern"] = new ToolProperty
			{
				Type = "string",
				Description = "File extension filter (e.g. '.cs', '.py'). Optional, shows all files if omitted."
			}
		},
		Required = new List<string>()
	};

	public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
	{
		JsonElement value;
		string text = (args.TryGetProperty("path", out value) ? (value.GetString() ?? "") : "");
		int num = 3;
		if (args.TryGetProperty("depth", out var value2))
		{
			int result;
			if (value2.ValueKind == JsonValueKind.Number)
			{
				num = value2.GetInt32();
			}
			else if (value2.ValueKind == JsonValueKind.String && int.TryParse(value2.GetString(), out result))
			{
				num = result;
			}
		}
		string s = num.ToString();
		bool includeFiles = true;
		if (args.TryGetProperty("include_files", out var value3))
		{
			includeFiles = ((value3.ValueKind != JsonValueKind.True && value3.ValueKind != JsonValueKind.False) ? (!string.Equals(value3.GetString(), "false", StringComparison.OrdinalIgnoreCase)) : value3.GetBoolean());
		}
		JsonElement value4;
		string extFilter = (args.TryGetProperty("pattern", out value4) ? (value4.GetString() ?? "") : "");
		if (!int.TryParse(s, out var result2) || result2 < 1)
		{
			result2 = 3;
		}
		result2 = Math.Min(result2, 10);
		string text2 = (string.IsNullOrEmpty(text) ? context.WorkFolder : FileReadTool.ResolvePath(text, context.WorkFolder));
		if (string.IsNullOrEmpty(text2) || !Directory.Exists(text2))
		{
			return Task.FromResult(ToolResult.Fail("디렉토리가 존재하지 않습니다: " + text2));
		}
		if (!context.IsPathAllowed(text2))
		{
			return Task.FromResult(ToolResult.Fail("경로 접근 차단: " + text2));
		}
		try
		{
			StringBuilder stringBuilder = new StringBuilder();
			string value5 = Path.GetFileName(text2);
			if (string.IsNullOrEmpty(value5))
			{
				value5 = text2;
			}
			StringBuilder stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder3 = stringBuilder2;
			StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(1, 1, stringBuilder2);
			handler.AppendFormatted(value5);
			handler.AppendLiteral("/");
			stringBuilder3.AppendLine(ref handler);
			int entryCount = 0;
			BuildTree(stringBuilder, text2, "", 0, result2, includeFiles, extFilter, context, ref entryCount);
			if (entryCount >= 500)
			{
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(42, 1, stringBuilder2);
				handler.AppendLiteral("\n... (");
				handler.AppendFormatted(500);
				handler.AppendLiteral("개 항목 제한 도달, depth 또는 pattern을 조정하세요)");
				stringBuilder4.AppendLine(ref handler);
			}
			string value6 = $"폴더 맵 생성 완료 ({entryCount}개 항목, 깊이 {result2})";
			return Task.FromResult(ToolResult.Ok($"{value6}\n\n{stringBuilder}"));
		}
		catch (Exception ex)
		{
			return Task.FromResult(ToolResult.Fail("폴더 맵 생성 실패: " + ex.Message));
		}
	}

	private static void BuildTree(StringBuilder sb, string dir, string prefix, int currentDepth, int maxDepth, bool includeFiles, string extFilter, AgentContext context, ref int entryCount)
	{
		if (currentDepth >= maxDepth || entryCount >= 500)
		{
			return;
		}
		List<DirectoryInfo> list;
		try
		{
			list = (from d in new DirectoryInfo(dir).GetDirectories()
				where !d.Attributes.HasFlag(FileAttributes.Hidden) && !IgnoredDirs.Contains(d.Name)
				orderby d.Name
				select d).ToList();
		}
		catch
		{
			return;
		}
		List<FileInfo> list2 = new List<FileInfo>();
		if (includeFiles)
		{
			try
			{
				list2 = (from f in new DirectoryInfo(dir).GetFiles()
					where !f.Attributes.HasFlag(FileAttributes.Hidden) && (string.IsNullOrEmpty(extFilter) || f.Extension.Equals(extFilter, StringComparison.OrdinalIgnoreCase))
					orderby f.Name
					select f).ToList();
			}
			catch
			{
			}
		}
		int num = list.Count + list2.Count;
		int num2 = 0;
		foreach (DirectoryInfo item in list)
		{
			if (entryCount >= 500)
			{
				break;
			}
			num2++;
			bool flag = num2 == num;
			string value = (flag ? "└── " : "├── ");
			string text = (flag ? "    " : "│   ");
			StringBuilder stringBuilder = sb;
			StringBuilder stringBuilder2 = stringBuilder;
			StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(1, 3, stringBuilder);
			handler.AppendFormatted(prefix);
			handler.AppendFormatted(value);
			handler.AppendFormatted(item.Name);
			handler.AppendLiteral("/");
			stringBuilder2.AppendLine(ref handler);
			entryCount++;
			if (context.IsPathAllowed(item.FullName))
			{
				BuildTree(sb, item.FullName, prefix + text, currentDepth + 1, maxDepth, includeFiles, extFilter, context, ref entryCount);
			}
		}
		foreach (FileInfo item2 in list2)
		{
			if (entryCount >= 500)
			{
				break;
			}
			num2++;
			string value2 = ((num2 == num) ? "└── " : "├── ");
			string value3 = FormatSize(item2.Length);
			StringBuilder stringBuilder = sb;
			StringBuilder stringBuilder3 = stringBuilder;
			StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(4, 4, stringBuilder);
			handler.AppendFormatted(prefix);
			handler.AppendFormatted(value2);
			handler.AppendFormatted(item2.Name);
			handler.AppendLiteral("  (");
			handler.AppendFormatted(value3);
			handler.AppendLiteral(")");
			stringBuilder3.AppendLine(ref handler);
			entryCount++;
		}
	}

	private static string FormatSize(long bytes)
	{
		if (1 == 0)
		{
		}
		string result = ((bytes < 1024) ? $"{bytes} B" : ((bytes >= 1048576) ? $"{(double)bytes / 1048576.0:F1} MB" : $"{(double)bytes / 1024.0:F1} KB"));
		if (1 == 0)
		{
		}
		return result;
	}
}
