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

namespace AxCopilot.Services.Agent;

public class FormatConvertTool : IAgentTool
{
	public string Name => "format_convert";

	public string Description => "Convert a document between formats. Supports: md→html (Markdown to styled HTML with mood CSS), html→text (strip HTML tags to plain text), csv→html (CSV to HTML table). For complex conversions (docx↔html, xlsx↔csv), read the source with document_read/file_read, then use the appropriate creation skill (html_create, docx_create, etc.).";

	public ToolParameterSchema Parameters
	{
		get
		{
			ToolParameterSchema obj = new ToolParameterSchema
			{
				Properties = new Dictionary<string, ToolProperty>
				{
					["source"] = new ToolProperty
					{
						Type = "string",
						Description = "Source file path to convert"
					},
					["target"] = new ToolProperty
					{
						Type = "string",
						Description = "Target output file path (extension determines format)"
					},
					["mood"] = new ToolProperty
					{
						Type = "string",
						Description = "Design mood for HTML output (default: modern). Only used for md→html conversion."
					}
				}
			};
			int num = 2;
			List<string> list = new List<string>(num);
			CollectionsMarshal.SetCount(list, num);
			Span<string> span = CollectionsMarshal.AsSpan(list);
			span[0] = "source";
			span[1] = "target";
			obj.Required = list;
			return obj;
		}
	}

	public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
	{
		string source = args.GetProperty("source").GetString() ?? "";
		string target = args.GetProperty("target").GetString() ?? "";
		JsonElement m;
		string mood = (args.TryGetProperty("mood", out m) ? (m.GetString() ?? "modern") : "modern");
		string srcPath = FileReadTool.ResolvePath(source, context.WorkFolder);
		string tgtPath = FileReadTool.ResolvePath(target, context.WorkFolder);
		if (context.ActiveTab == "Cowork")
		{
			tgtPath = AgentContext.EnsureTimestampedPath(tgtPath);
		}
		if (!context.IsPathAllowed(srcPath))
		{
			return ToolResult.Fail("소스 경로 접근 차단: " + srcPath);
		}
		if (!context.IsPathAllowed(tgtPath))
		{
			return ToolResult.Fail("대상 경로 접근 차단: " + tgtPath);
		}
		if (!File.Exists(srcPath))
		{
			return ToolResult.Fail("소스 파일 없음: " + srcPath);
		}
		if (!(await context.CheckWritePermissionAsync("format_convert", tgtPath)))
		{
			return ToolResult.Fail("쓰기 권한이 거부되었습니다.");
		}
		string srcExt = Path.GetExtension(srcPath).ToLowerInvariant();
		string tgtExt = Path.GetExtension(tgtPath).ToLowerInvariant();
		string convKey = srcExt + "→" + tgtExt;
		try
		{
			string srcContent = await File.ReadAllTextAsync(srcPath, ct);
			string result;
			switch (convKey)
			{
			case ".md→.html":
			{
				MarkdownPipeline pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
				string bodyHtml = Markdown.ToHtml(srcContent, pipeline);
				string css = TemplateService.GetCss(mood);
				result = $"<!DOCTYPE html>\n<html lang=\"ko\">\n<head>\n<meta charset=\"UTF-8\"/>\n<style>{css}</style>\n</head>\n<body>\n<div class=\"container\">\n{bodyHtml}\n</div>\n</body>\n</html>";
				break;
			}
			case ".html→.txt":
			case ".htm→.txt":
				result = StripHtmlTags(srcContent);
				break;
			case ".csv→.html":
				result = CsvToHtmlTable(srcContent, mood);
				break;
			case ".md→.txt":
				result = StripMarkdown(srcContent);
				break;
			default:
				return ToolResult.Fail("직접 변환 미지원: " + convKey + "\n대안: source를 file_read/document_read로 읽은 뒤, 적절한 생성 스킬(html_create, docx_create, excel_create 등)을 사용하세요.");
			}
			string dir = Path.GetDirectoryName(tgtPath);
			if (!string.IsNullOrEmpty(dir))
			{
				Directory.CreateDirectory(dir);
			}
			await File.WriteAllTextAsync(tgtPath, result, ct);
			string srcName = Path.GetFileName(srcPath);
			string tgtName = Path.GetFileName(tgtPath);
			return ToolResult.Ok($"변환 완료: {srcName} → {tgtName}\n변환 유형: {convKey}\n출력 크기: {result.Length:N0}자", tgtPath);
		}
		catch (Exception ex)
		{
			return ToolResult.Fail("변환 오류: " + ex.Message);
		}
	}

	private static string StripHtmlTags(string html)
	{
		string input = Regex.Replace(html, "<(script|style)[^>]*>.*?</\\1>", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
		input = Regex.Replace(input, "<br\\s*/?>", "\n", RegexOptions.IgnoreCase);
		input = Regex.Replace(input, "</(p|div|h[1-6]|li|tr)>", "\n", RegexOptions.IgnoreCase);
		input = Regex.Replace(input, "<[^>]+>", "");
		input = WebUtility.HtmlDecode(input);
		input = Regex.Replace(input, "\\n{3,}", "\n\n");
		return input.Trim();
	}

	private static string StripMarkdown(string md)
	{
		string input = md;
		input = Regex.Replace(input, "^#{1,6}\\s+", "", RegexOptions.Multiline);
		input = Regex.Replace(input, "\\*\\*(.+?)\\*\\*", "$1");
		input = Regex.Replace(input, "\\*(.+?)\\*", "$1");
		input = Regex.Replace(input, "`(.+?)`", "$1");
		input = Regex.Replace(input, "^\\s*[-*+]\\s+", "", RegexOptions.Multiline);
		input = Regex.Replace(input, "^\\s*\\d+\\.\\s+", "", RegexOptions.Multiline);
		input = Regex.Replace(input, "\\[(.+?)\\]\\(.+?\\)", "$1");
		return input.Trim();
	}

	private static string CsvToHtmlTable(string csv, string mood)
	{
		string[] array = csv.Split('\n', StringSplitOptions.RemoveEmptyEntries);
		if (array.Length == 0)
		{
			return "<p>빈 CSV 파일</p>";
		}
		string css = TemplateService.GetCss(mood);
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("<!DOCTYPE html>\n<html lang=\"ko\">\n<head>\n<meta charset=\"UTF-8\"/>");
		StringBuilder stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder3 = stringBuilder2;
		StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(54, 1, stringBuilder2);
		handler.AppendLiteral("<style>");
		handler.AppendFormatted(css);
		handler.AppendLiteral("</style>\n</head>\n<body>\n<div class=\"container\">");
		stringBuilder3.AppendLine(ref handler);
		stringBuilder.AppendLine("<table><thead><tr>");
		string[] array2 = ParseCsvLine(array[0]);
		string[] array3 = array2;
		foreach (string value in array3)
		{
			stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder4 = stringBuilder2;
			handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
			handler.AppendLiteral("<th>");
			handler.AppendFormatted(WebUtility.HtmlEncode(value));
			handler.AppendLiteral("</th>");
			stringBuilder4.Append(ref handler);
		}
		stringBuilder.AppendLine("</tr></thead><tbody>");
		for (int j = 1; j < Math.Min(array.Length, 1001); j++)
		{
			string[] array4 = ParseCsvLine(array[j]);
			stringBuilder.Append("<tr>");
			string[] array5 = array4;
			foreach (string value2 in array5)
			{
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder5 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
				handler.AppendLiteral("<td>");
				handler.AppendFormatted(WebUtility.HtmlEncode(value2));
				handler.AppendLiteral("</td>");
				stringBuilder5.Append(ref handler);
			}
			stringBuilder.AppendLine("</tr>");
		}
		stringBuilder.AppendLine("</tbody></table>\n</div>\n</body>\n</html>");
		return stringBuilder.ToString();
	}

	private static string[] ParseCsvLine(string line)
	{
		List<string> list = new List<string>();
		StringBuilder stringBuilder = new StringBuilder();
		bool flag = false;
		for (int i = 0; i < line.Length; i++)
		{
			char c = line[i];
			if (flag)
			{
				if (c == '"' && i + 1 < line.Length && line[i + 1] == '"')
				{
					stringBuilder.Append('"');
					i++;
				}
				else if (c == '"')
				{
					flag = false;
				}
				else
				{
					stringBuilder.Append(c);
				}
				continue;
			}
			switch (c)
			{
			case '"':
				flag = true;
				break;
			case ',':
				list.Add(stringBuilder.ToString());
				stringBuilder.Clear();
				break;
			default:
				stringBuilder.Append(c);
				break;
			}
		}
		list.Add(stringBuilder.ToString());
		return list.ToArray();
	}
}
