using System;
using System.Collections.Generic;
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 EncodingTool : IAgentTool
{
	public string Name => "encoding_tool";

	public string Description => "Detect and convert file text encoding. Actions: 'detect' — detect file encoding (UTF-8, EUC-KR, etc.); 'convert' — convert file from one encoding to another; 'list' — list common encoding names.";

	public ToolParameterSchema Parameters
	{
		get
		{
			ToolParameterSchema toolParameterSchema = new ToolParameterSchema();
			Dictionary<string, ToolProperty> dictionary = new Dictionary<string, ToolProperty>();
			ToolProperty obj = new ToolProperty
			{
				Type = "string",
				Description = "Action: detect, convert, list"
			};
			int num = 3;
			List<string> list = new List<string>(num);
			CollectionsMarshal.SetCount(list, num);
			Span<string> span = CollectionsMarshal.AsSpan(list);
			span[0] = "detect";
			span[1] = "convert";
			span[2] = "list";
			obj.Enum = list;
			dictionary["action"] = obj;
			dictionary["path"] = new ToolProperty
			{
				Type = "string",
				Description = "File path"
			};
			dictionary["from_encoding"] = new ToolProperty
			{
				Type = "string",
				Description = "Source encoding name (e.g. 'euc-kr', 'shift-jis'). Auto-detected if omitted."
			};
			dictionary["to_encoding"] = new ToolProperty
			{
				Type = "string",
				Description = "Target encoding name (default: 'utf-8')"
			};
			toolParameterSchema.Properties = dictionary;
			num = 1;
			List<string> list2 = new List<string>(num);
			CollectionsMarshal.SetCount(list2, num);
			CollectionsMarshal.AsSpan(list2)[0] = "action";
			toolParameterSchema.Required = list2;
			return toolParameterSchema;
		}
	}

	public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken))
	{
		string action = args.GetProperty("action").GetString() ?? "";
		if (action == "list")
		{
			return ListEncodings();
		}
		JsonElement pv;
		string rawPath = (args.TryGetProperty("path", out pv) ? (pv.GetString() ?? "") : "");
		if (string.IsNullOrEmpty(rawPath))
		{
			return ToolResult.Fail("'path'가 필요합니다.");
		}
		string path = (Path.IsPathRooted(rawPath) ? rawPath : Path.Combine(context.WorkFolder, rawPath));
		if (!context.IsPathAllowed(path))
		{
			return ToolResult.Fail("경로 접근 차단: " + path);
		}
		if (!File.Exists(path))
		{
			return ToolResult.Fail("파일 없음: " + path);
		}
		try
		{
			if (1 == 0)
			{
			}
			string text = action;
			ToolResult result = ((text == "detect") ? DetectEncoding(path) : ((!(text == "convert")) ? ToolResult.Fail("Unknown action: " + action) : (await ConvertEncoding(path, args, context))));
			if (1 == 0)
			{
			}
			return result;
		}
		catch (Exception ex)
		{
			return ToolResult.Fail("인코딩 처리 오류: " + ex.Message);
		}
	}

	private static ToolResult DetectEncoding(string path)
	{
		byte[] array = File.ReadAllBytes(path);
		Encoding encoding = DetectEncodingFromBytes(array);
		StringBuilder stringBuilder = new StringBuilder();
		StringBuilder stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder3 = stringBuilder2;
		StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(6, 1, stringBuilder2);
		handler.AppendLiteral("File: ");
		handler.AppendFormatted(Path.GetFileName(path));
		stringBuilder3.AppendLine(ref handler);
		stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder4 = stringBuilder2;
		handler = new StringBuilder.AppendInterpolatedStringHandler(12, 1, stringBuilder2);
		handler.AppendLiteral("Size: ");
		handler.AppendFormatted(array.Length, "N0");
		handler.AppendLiteral(" bytes");
		stringBuilder4.AppendLine(ref handler);
		stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder5 = stringBuilder2;
		handler = new StringBuilder.AppendInterpolatedStringHandler(19, 1, stringBuilder2);
		handler.AppendLiteral("Detected Encoding: ");
		handler.AppendFormatted(encoding.EncodingName);
		stringBuilder5.AppendLine(ref handler);
		stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder6 = stringBuilder2;
		handler = new StringBuilder.AppendInterpolatedStringHandler(11, 1, stringBuilder2);
		handler.AppendLiteral("Code Page: ");
		handler.AppendFormatted(encoding.CodePage);
		stringBuilder6.AppendLine(ref handler);
		stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder7 = stringBuilder2;
		handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder2);
		handler.AppendLiteral("BOM Present: ");
		handler.AppendFormatted(HasBom(array));
		stringBuilder7.AppendLine(ref handler);
		return ToolResult.Ok(stringBuilder.ToString());
	}

	private static async Task<ToolResult> ConvertEncoding(string path, JsonElement args, AgentContext context)
	{
		JsonElement te;
		string toName = (args.TryGetProperty("to_encoding", out te) ? (te.GetString() ?? "utf-8") : "utf-8");
		if (!(await context.CheckWritePermissionAsync("encoding_tool", path)))
		{
			return ToolResult.Fail("파일 쓰기 권한이 거부되었습니다.");
		}
		Encoding fromEnc;
		if (args.TryGetProperty("from_encoding", out var fe) && !string.IsNullOrEmpty(fe.GetString()))
		{
			Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
			fromEnc = Encoding.GetEncoding(fe.GetString());
		}
		else
		{
			byte[] rawBytes = File.ReadAllBytes(path);
			fromEnc = DetectEncodingFromBytes(rawBytes);
		}
		Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
		Encoding toEnc = Encoding.GetEncoding(toName);
		string content = File.ReadAllText(path, fromEnc);
		File.WriteAllText(path, content, toEnc);
		return ToolResult.Ok($"변환 완료: {fromEnc.EncodingName} → {toEnc.EncodingName}\nFile: {path}", path);
	}

	private static ToolResult ListEncodings()
	{
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("주요 인코딩 목록:");
		stringBuilder.AppendLine("  utf-8       — UTF-8 (유니코드, 기본)");
		stringBuilder.AppendLine("  utf-16      — UTF-16 LE");
		stringBuilder.AppendLine("  utf-16BE    — UTF-16 BE");
		stringBuilder.AppendLine("  euc-kr      — EUC-KR (한국어)");
		stringBuilder.AppendLine("  ks_c_5601-1987 — 한글 완성형");
		stringBuilder.AppendLine("  shift_jis   — Shift-JIS (일본어)");
		stringBuilder.AppendLine("  gb2312      — GB2312 (중국어 간체)");
		stringBuilder.AppendLine("  iso-8859-1  — Latin-1 (서유럽)");
		stringBuilder.AppendLine("  ascii       — US-ASCII");
		stringBuilder.AppendLine("  utf-32      — UTF-32");
		return ToolResult.Ok(stringBuilder.ToString());
	}

	private static Encoding DetectEncodingFromBytes(byte[] bytes)
	{
		if (bytes.Length >= 3 && bytes[0] == 239 && bytes[1] == 187 && bytes[2] == 191)
		{
			return Encoding.UTF8;
		}
		if (bytes.Length >= 2 && bytes[0] == byte.MaxValue && bytes[1] == 254)
		{
			return Encoding.Unicode;
		}
		if (bytes.Length >= 2 && bytes[0] == 254 && bytes[1] == byte.MaxValue)
		{
			return Encoding.BigEndianUnicode;
		}
		if (IsValidUtf8(bytes))
		{
			return Encoding.UTF8;
		}
		Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
		try
		{
			return Encoding.GetEncoding("euc-kr");
		}
		catch
		{
			return Encoding.Default;
		}
	}

	private static bool IsValidUtf8(byte[] bytes)
	{
		int num = 0;
		bool flag = false;
		while (num < bytes.Length)
		{
			if (bytes[num] <= 127)
			{
				num++;
				continue;
			}
			int num2;
			if ((bytes[num] & 0xE0) == 192)
			{
				num2 = 1;
			}
			else if ((bytes[num] & 0xF0) == 224)
			{
				num2 = 2;
			}
			else
			{
				if ((bytes[num] & 0xF8) != 240)
				{
					return false;
				}
				num2 = 3;
			}
			if (num + num2 >= bytes.Length)
			{
				return false;
			}
			for (int i = 1; i <= num2; i++)
			{
				if ((bytes[num + i] & 0xC0) != 128)
				{
					return false;
				}
			}
			flag = true;
			num += num2 + 1;
		}
		return flag || bytes.Length < 100;
	}

	private static bool HasBom(byte[] bytes)
	{
		if (bytes.Length >= 3 && bytes[0] == 239 && bytes[1] == 187 && bytes[2] == 191)
		{
			return true;
		}
		if (bytes.Length >= 2 && bytes[0] == byte.MaxValue && bytes[1] == 254)
		{
			return true;
		}
		if (bytes.Length >= 2 && bytes[0] == 254 && bytes[1] == byte.MaxValue)
		{
			return true;
		}
		return false;
	}
}
