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

namespace AxCopilot.Services.Agent;

public class ZipTool : IAgentTool
{
	private const long MaxExtractSize = 524288000L;

	public string Name => "zip_tool";

	public string Description => "Compress or extract zip archives. Actions: 'compress' — create a zip file from files/folders; 'extract' — extract a zip file to a directory; 'list' — list contents of a zip file without extracting.";

	public ToolParameterSchema Parameters
	{
		get
		{
			ToolParameterSchema toolParameterSchema = new ToolParameterSchema();
			Dictionary<string, ToolProperty> dictionary = new Dictionary<string, ToolProperty>();
			ToolProperty obj = new ToolProperty
			{
				Type = "string",
				Description = "Action to perform"
			};
			int num = 3;
			List<string> list = new List<string>(num);
			CollectionsMarshal.SetCount(list, num);
			Span<string> span = CollectionsMarshal.AsSpan(list);
			span[0] = "compress";
			span[1] = "extract";
			span[2] = "list";
			obj.Enum = list;
			dictionary["action"] = obj;
			dictionary["zip_path"] = new ToolProperty
			{
				Type = "string",
				Description = "Path to the zip file (to create or extract)"
			};
			dictionary["source_path"] = new ToolProperty
			{
				Type = "string",
				Description = "Source file or directory path (for compress action)"
			};
			dictionary["dest_path"] = new ToolProperty
			{
				Type = "string",
				Description = "Destination directory (for extract action)"
			};
			toolParameterSchema.Properties = dictionary;
			num = 2;
			List<string> list2 = new List<string>(num);
			CollectionsMarshal.SetCount(list2, num);
			Span<string> span2 = CollectionsMarshal.AsSpan(list2);
			span2[0] = "action";
			span2[1] = "zip_path";
			toolParameterSchema.Required = list2;
			return toolParameterSchema;
		}
	}

	public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken))
	{
		string text = args.GetProperty("action").GetString() ?? "";
		string text2 = args.GetProperty("zip_path").GetString() ?? "";
		if (!Path.IsPathRooted(text2))
		{
			text2 = Path.Combine(context.WorkFolder, text2);
		}
		try
		{
			if (1 == 0)
			{
			}
			ToolResult result = text switch
			{
				"compress" => Compress(args, text2, context), 
				"extract" => Extract(args, text2, context), 
				"list" => ListContents(text2), 
				_ => ToolResult.Fail("Unknown action: " + text), 
			};
			if (1 == 0)
			{
			}
			return Task.FromResult(result);
		}
		catch (Exception ex)
		{
			return Task.FromResult(ToolResult.Fail("Zip 오류: " + ex.Message));
		}
	}

	private static ToolResult Compress(JsonElement args, string zipPath, AgentContext context)
	{
		if (!args.TryGetProperty("source_path", out var value))
		{
			return ToolResult.Fail("'source_path' is required for compress action");
		}
		string text = value.GetString() ?? "";
		if (!Path.IsPathRooted(text))
		{
			text = Path.Combine(context.WorkFolder, text);
		}
		if (File.Exists(zipPath))
		{
			return ToolResult.Fail("Zip file already exists: " + zipPath);
		}
		if (Directory.Exists(text))
		{
			ZipFile.CreateFromDirectory(text, zipPath, CompressionLevel.Optimal, includeBaseDirectory: false);
			FileInfo fileInfo = new FileInfo(zipPath);
			return ToolResult.Ok($"✓ Created {zipPath} ({fileInfo.Length / 1024}KB)", zipPath);
		}
		if (File.Exists(text))
		{
			using (ZipArchive destination = ZipFile.Open(zipPath, ZipArchiveMode.Create))
			{
				destination.CreateEntryFromFile(text, Path.GetFileName(text), CompressionLevel.Optimal);
				FileInfo fileInfo2 = new FileInfo(zipPath);
				return ToolResult.Ok($"✓ Created {zipPath} ({fileInfo2.Length / 1024}KB)", zipPath);
			}
		}
		return ToolResult.Fail("Source not found: " + text);
	}

	private static ToolResult Extract(JsonElement args, string zipPath, AgentContext context)
	{
		if (!File.Exists(zipPath))
		{
			return ToolResult.Fail("Zip file not found: " + zipPath);
		}
		JsonElement value;
		string text = (args.TryGetProperty("dest_path", out value) ? (value.GetString() ?? "") : "");
		if (string.IsNullOrEmpty(text))
		{
			text = Path.Combine(Path.GetDirectoryName(zipPath) ?? context.WorkFolder, Path.GetFileNameWithoutExtension(zipPath));
		}
		if (!Path.IsPathRooted(text))
		{
			text = Path.Combine(context.WorkFolder, text);
		}
		using (ZipArchive zipArchive = ZipFile.OpenRead(zipPath))
		{
			long num = zipArchive.Entries.Sum((ZipArchiveEntry e) => e.Length);
			if (num > 524288000)
			{
				return ToolResult.Fail($"Uncompressed size ({num / 1024 / 1024}MB) exceeds 500MB limit");
			}
			foreach (ZipArchiveEntry entry in zipArchive.Entries)
			{
				string fullPath = Path.GetFullPath(Path.Combine(text, entry.FullName));
				if (!fullPath.StartsWith(Path.GetFullPath(text), StringComparison.OrdinalIgnoreCase))
				{
					return ToolResult.Fail("Security: entry '" + entry.FullName + "' escapes destination directory");
				}
			}
		}
		Directory.CreateDirectory(text);
		ZipFile.ExtractToDirectory(zipPath, text, overwriteFiles: true);
		int value2 = Directory.GetFiles(text, "*", SearchOption.AllDirectories).Length;
		return ToolResult.Ok($"✓ Extracted {value2} files to {text}");
	}

	private static ToolResult ListContents(string zipPath)
	{
		if (!File.Exists(zipPath))
		{
			return ToolResult.Fail("Zip file not found: " + zipPath);
		}
		using ZipArchive zipArchive = ZipFile.OpenRead(zipPath);
		StringBuilder stringBuilder = new StringBuilder();
		StringBuilder stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder3 = stringBuilder2;
		StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(14, 2, stringBuilder2);
		handler.AppendLiteral("Archive: ");
		handler.AppendFormatted(Path.GetFileName(zipPath));
		handler.AppendLiteral(" (");
		handler.AppendFormatted(new FileInfo(zipPath).Length / 1024);
		handler.AppendLiteral("KB)");
		stringBuilder3.AppendLine(ref handler);
		stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder4 = stringBuilder2;
		handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
		handler.AppendLiteral("Entries: ");
		handler.AppendFormatted(zipArchive.Entries.Count);
		stringBuilder4.AppendLine(ref handler);
		stringBuilder.AppendLine();
		stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder5 = stringBuilder2;
		handler = new StringBuilder.AppendInterpolatedStringHandler(4, 3, stringBuilder2);
		handler.AppendFormatted<string>("Size", 10);
		handler.AppendLiteral("  ");
		handler.AppendFormatted<string>("Compressed", 10);
		handler.AppendLiteral("  ");
		handler.AppendFormatted("Name");
		stringBuilder5.AppendLine(ref handler);
		stringBuilder.AppendLine(new string('-', 60));
		int num = Math.Min(zipArchive.Entries.Count, 200);
		foreach (ZipArchiveEntry item in zipArchive.Entries.Take(num))
		{
			stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder6 = stringBuilder2;
			handler = new StringBuilder.AppendInterpolatedStringHandler(4, 3, stringBuilder2);
			handler.AppendFormatted(item.Length, 10);
			handler.AppendLiteral("  ");
			handler.AppendFormatted(item.CompressedLength, 10);
			handler.AppendLiteral("  ");
			handler.AppendFormatted(item.FullName);
			stringBuilder6.AppendLine(ref handler);
		}
		if (zipArchive.Entries.Count > num)
		{
			stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder7 = stringBuilder2;
			handler = new StringBuilder.AppendInterpolatedStringHandler(22, 1, stringBuilder2);
			handler.AppendLiteral("\n... and ");
			handler.AppendFormatted(zipArchive.Entries.Count - num);
			handler.AppendLiteral(" more entries");
			stringBuilder7.AppendLine(ref handler);
		}
		long num2 = zipArchive.Entries.Sum((ZipArchiveEntry e) => e.Length);
		stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder8 = stringBuilder2;
		handler = new StringBuilder.AppendInterpolatedStringHandler(23, 1, stringBuilder2);
		handler.AppendLiteral("\nTotal uncompressed: ");
		handler.AppendFormatted(num2 / 1024);
		handler.AppendLiteral("KB");
		stringBuilder8.AppendLine(ref handler);
		return ToolResult.Ok(stringBuilder.ToString());
	}
}
