using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

namespace AxCopilot.Services.Agent;

public class DocumentAssemblerTool : IAgentTool
{
	public string Name => "document_assemble";

	public string Description => "Assemble multiple individually-written sections into a single complete document. Use this after writing each section separately with document_plan. Supports HTML, DOCX, and Markdown output. Automatically adds table of contents, cover page, and section numbering for HTML. After assembly, the document is auto-validated for quality issues.";

	public ToolParameterSchema Parameters
	{
		get
		{
			ToolParameterSchema toolParameterSchema = new ToolParameterSchema();
			Dictionary<string, ToolProperty> obj = new Dictionary<string, ToolProperty>
			{
				["path"] = new ToolProperty
				{
					Type = "string",
					Description = "Output file path. Relative to work folder."
				},
				["title"] = new ToolProperty
				{
					Type = "string",
					Description = "Document title"
				},
				["sections"] = new ToolProperty
				{
					Type = "array",
					Description = "Array of section objects: [{\"heading\": \"1. 개요\", \"content\": \"HTML or markdown body...\", \"level\": 1}]. content should be the detailed text for each section.",
					Items = new ToolProperty
					{
						Type = "object"
					}
				}
			};
			ToolProperty obj2 = new ToolProperty
			{
				Type = "string",
				Description = "Output format: html, docx, markdown. Default: html"
			};
			int num = 3;
			List<string> list = new List<string>(num);
			CollectionsMarshal.SetCount(list, num);
			Span<string> span = CollectionsMarshal.AsSpan(list);
			span[0] = "html";
			span[1] = "docx";
			span[2] = "markdown";
			obj2.Enum = list;
			obj["format"] = obj2;
			obj["mood"] = new ToolProperty
			{
				Type = "string",
				Description = "Design theme for HTML output: modern, professional, creative, corporate, dashboard, etc. Default: professional"
			};
			obj["toc"] = new ToolProperty
			{
				Type = "boolean",
				Description = "Auto-generate table of contents. Default: true"
			};
			obj["cover_subtitle"] = new ToolProperty
			{
				Type = "string",
				Description = "Subtitle for cover page. If provided, a cover page is added."
			};
			obj["header"] = new ToolProperty
			{
				Type = "string",
				Description = "Header text for DOCX output."
			};
			obj["footer"] = new ToolProperty
			{
				Type = "string",
				Description = "Footer text for DOCX output. Use {page} for page number."
			};
			toolParameterSchema.Properties = obj;
			num = 3;
			List<string> list2 = new List<string>(num);
			CollectionsMarshal.SetCount(list2, num);
			Span<string> span2 = CollectionsMarshal.AsSpan(list2);
			span2[0] = "path";
			span2[1] = "title";
			span2[2] = "sections";
			toolParameterSchema.Required = list2;
			return toolParameterSchema;
		}
	}

	public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
	{
		string path = args.GetProperty("path").GetString() ?? "";
		string title = args.GetProperty("title").GetString() ?? "Document";
		JsonElement fmt;
		string format = (args.TryGetProperty("format", out fmt) ? (fmt.GetString() ?? "html") : "html");
		JsonElement m;
		string mood = (args.TryGetProperty("mood", out m) ? (m.GetString() ?? "professional") : "professional");
		JsonElement tocVal;
		bool useToc = !args.TryGetProperty("toc", out tocVal) || tocVal.GetBoolean();
		JsonElement cs;
		string coverSubtitle = (args.TryGetProperty("cover_subtitle", out cs) ? cs.GetString() : null);
		JsonElement hdr;
		string headerText = (args.TryGetProperty("header", out hdr) ? hdr.GetString() : null);
		JsonElement ftr;
		string footerText = (args.TryGetProperty("footer", out ftr) ? ftr.GetString() : null);
		if (!args.TryGetProperty("sections", out var sectionsEl) || sectionsEl.ValueKind != JsonValueKind.Array)
		{
			return ToolResult.Fail("sections 배열이 필요합니다.");
		}
		List<(string Heading, string Content, int Level)> sections = new List<(string, string, int)>();
		foreach (JsonElement sec in sectionsEl.EnumerateArray())
		{
			JsonElement h;
			string heading = (sec.TryGetProperty("heading", out h) ? (h.GetString() ?? "") : "");
			JsonElement c;
			string content = (sec.TryGetProperty("content", out c) ? (c.GetString() ?? "") : "");
			JsonElement lv;
			int level = ((!sec.TryGetProperty("level", out lv)) ? 1 : lv.GetInt32());
			if (!string.IsNullOrWhiteSpace(heading) || !string.IsNullOrWhiteSpace(content))
			{
				sections.Add((heading, content, level));
			}
			h = default(JsonElement);
			c = default(JsonElement);
			lv = default(JsonElement);
		}
		if (sections.Count == 0)
		{
			return ToolResult.Fail("조립할 섹션이 없습니다.");
		}
		string fullPath = FileReadTool.ResolvePath(path, context.WorkFolder);
		if (context.ActiveTab == "Cowork")
		{
			fullPath = AgentContext.EnsureTimestampedPath(fullPath);
		}
		if (1 == 0)
		{
		}
		string text = format;
		string text2 = ((text == "docx") ? ".docx" : ((!(text == "markdown")) ? ".html" : ".md"));
		if (1 == 0)
		{
		}
		string ext = text2;
		if (!fullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))
		{
			fullPath += ext;
		}
		if (!context.IsPathAllowed(fullPath))
		{
			return ToolResult.Fail("경로 접근 차단: " + fullPath);
		}
		if (!(await context.CheckWritePermissionAsync(Name, fullPath)))
		{
			return ToolResult.Fail("쓰기 권한 거부: " + fullPath);
		}
		string dir = Path.GetDirectoryName(fullPath);
		if (!string.IsNullOrEmpty(dir))
		{
			Directory.CreateDirectory(dir);
		}
		try
		{
			string text3 = format;
			text2 = text3;
			string resultMsg = ((text2 == "docx") ? AssembleDocx(fullPath, title, sections, headerText, footerText) : ((!(text2 == "markdown")) ? AssembleHtml(fullPath, title, sections, mood, useToc, coverSubtitle) : AssembleMarkdown(fullPath, title, sections)));
			int totalChars = sections.Sum<(string, string, int)>(((string Heading, string Content, int Level) s) => s.Content.Length);
			int totalWords = sections.Sum<(string, string, int)>(((string Heading, string Content, int Level) s) => EstimateWordCount(s.Content));
			int pageEstimate = Math.Max(1, totalWords / 500);
			return ToolResult.Ok($"✅ 문서 조립 완료: {Path.GetFileName(fullPath)}\n  섹션: {sections.Count}개 | 글자: {totalChars:N0} | 단어: ~{totalWords:N0} | 예상 페이지: ~{pageEstimate}\n{resultMsg}", fullPath);
		}
		catch (Exception ex)
		{
			return ToolResult.Fail("문서 조립 실패: " + ex.Message);
		}
	}

	private string AssembleHtml(string path, string title, List<(string Heading, string Content, int Level)> sections, string mood, bool toc, string? coverSubtitle)
	{
		StringBuilder stringBuilder = new StringBuilder();
		string css = TemplateService.GetCss(mood);
		TemplateMood mood2 = TemplateService.GetMood(mood);
		stringBuilder.AppendLine("<!DOCTYPE html>");
		stringBuilder.AppendLine("<html lang=\"ko\">");
		stringBuilder.AppendLine("<head>");
		stringBuilder.AppendLine("<meta charset=\"utf-8\">");
		StringBuilder stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder3 = stringBuilder2;
		StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(15, 1, stringBuilder2);
		handler.AppendLiteral("<title>");
		handler.AppendFormatted(Escape(title));
		handler.AppendLiteral("</title>");
		stringBuilder3.AppendLine(ref handler);
		stringBuilder.AppendLine("<style>");
		stringBuilder.AppendLine(css);
		stringBuilder.AppendLine("\n.assembled-doc { max-width: 900px; margin: 0 auto; padding: 40px 30px 60px; }\n.assembled-doc h1 { font-size: 28px; margin-bottom: 8px; }\n.assembled-doc h2 { font-size: 22px; margin-top: 36px; margin-bottom: 12px; border-bottom: 2px solid var(--accent, #4B5EFC); padding-bottom: 6px; }\n.assembled-doc h3 { font-size: 18px; margin-top: 24px; margin-bottom: 8px; }\n.assembled-doc .section-content { line-height: 1.8; margin-bottom: 20px; }\n.assembled-doc .toc { background: #f8f9fa; border-radius: 12px; padding: 20px 28px; margin: 24px 0 32px; }\n.assembled-doc .toc h3 { margin-top: 0; }\n.assembled-doc .toc a { color: inherit; text-decoration: none; }\n.assembled-doc .toc a:hover { text-decoration: underline; }\n.assembled-doc .toc ul { list-style: none; padding-left: 0; }\n.assembled-doc .toc li { padding: 4px 0; }\n.cover-page { text-align: center; padding: 120px 40px 80px; page-break-after: always; }\n.cover-page h1 { font-size: 36px; margin-bottom: 16px; }\n.cover-page .subtitle { font-size: 18px; color: #666; margin-bottom: 40px; }\n.cover-page .date { font-size: 14px; color: #999; }\n@media print { .cover-page { page-break-after: always; } .assembled-doc h2 { page-break-before: auto; } }\n");
		stringBuilder.AppendLine("</style>");
		stringBuilder.AppendLine("</head>");
		stringBuilder.AppendLine("<body>");
		if (!string.IsNullOrWhiteSpace(coverSubtitle))
		{
			stringBuilder.AppendLine("<div class=\"cover-page\">");
			stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder4 = stringBuilder2;
			handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
			handler.AppendLiteral("<h1>");
			handler.AppendFormatted(Escape(title));
			handler.AppendLiteral("</h1>");
			stringBuilder4.AppendLine(ref handler);
			stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder5 = stringBuilder2;
			handler = new StringBuilder.AppendInterpolatedStringHandler(28, 1, stringBuilder2);
			handler.AppendLiteral("<div class=\"subtitle\">");
			handler.AppendFormatted(Escape(coverSubtitle));
			handler.AppendLiteral("</div>");
			stringBuilder5.AppendLine(ref handler);
			stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder6 = stringBuilder2;
			handler = new StringBuilder.AppendInterpolatedStringHandler(24, 1, stringBuilder2);
			handler.AppendLiteral("<div class=\"date\">");
			handler.AppendFormatted(DateTime.Now, "yyyy년 MM월 dd일");
			handler.AppendLiteral("</div>");
			stringBuilder6.AppendLine(ref handler);
			stringBuilder.AppendLine("</div>");
		}
		stringBuilder.AppendLine("<div class=\"assembled-doc\">");
		if (string.IsNullOrWhiteSpace(coverSubtitle))
		{
			stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder7 = stringBuilder2;
			handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
			handler.AppendLiteral("<h1>");
			handler.AppendFormatted(Escape(title));
			handler.AppendLiteral("</h1>");
			stringBuilder7.AppendLine(ref handler);
		}
		if (toc && sections.Count > 1)
		{
			stringBuilder.AppendLine("<div class=\"toc\">");
			stringBuilder.AppendLine("<h3>\ud83d\udccb 목차</h3>");
			stringBuilder.AppendLine("<ul>");
			for (int i = 0; i < sections.Count; i++)
			{
				string value = ((sections[i].Level > 1) ? " style=\"padding-left:20px\"" : "");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder8 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(33, 3, stringBuilder2);
				handler.AppendLiteral("<li");
				handler.AppendFormatted(value);
				handler.AppendLiteral("><a href=\"#section-");
				handler.AppendFormatted(i + 1);
				handler.AppendLiteral("\">");
				handler.AppendFormatted(Escape(sections[i].Heading));
				handler.AppendLiteral("</a></li>");
				stringBuilder8.AppendLine(ref handler);
			}
			stringBuilder.AppendLine("</ul>");
			stringBuilder.AppendLine("</div>");
		}
		for (int j = 0; j < sections.Count; j++)
		{
			(string Heading, string Content, int Level) tuple = sections[j];
			string item = tuple.Heading;
			string item2 = tuple.Content;
			int item3 = tuple.Level;
			string value2 = ((item3 <= 1) ? "h2" : "h3");
			stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder9 = stringBuilder2;
			handler = new StringBuilder.AppendInterpolatedStringHandler(19, 4, stringBuilder2);
			handler.AppendLiteral("<");
			handler.AppendFormatted(value2);
			handler.AppendLiteral(" id=\"section-");
			handler.AppendFormatted(j + 1);
			handler.AppendLiteral("\">");
			handler.AppendFormatted(Escape(item));
			handler.AppendLiteral("</");
			handler.AppendFormatted(value2);
			handler.AppendLiteral(">");
			stringBuilder9.AppendLine(ref handler);
			stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder10 = stringBuilder2;
			handler = new StringBuilder.AppendInterpolatedStringHandler(35, 1, stringBuilder2);
			handler.AppendLiteral("<div class=\"section-content\">");
			handler.AppendFormatted(item2);
			handler.AppendLiteral("</div>");
			stringBuilder10.AppendLine(ref handler);
		}
		stringBuilder.AppendLine("</div>");
		stringBuilder.AppendLine("</body>");
		stringBuilder.AppendLine("</html>");
		File.WriteAllText(path, stringBuilder.ToString(), Encoding.UTF8);
		List<string> list = ValidateBasic(stringBuilder.ToString());
		return (list.Count > 0) ? $"  ⚠ 품질 검증 이슈 {list.Count}건: {string.Join("; ", list)}" : "  ✓ 품질 검증 통과";
	}

	private string AssembleDocx(string path, string title, List<(string Heading, string Content, int Level)> sections, string? headerText, string? footerText)
	{
		using WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Create(path, WordprocessingDocumentType.Document);
		MainDocumentPart mainDocumentPart = wordprocessingDocument.AddMainDocumentPart();
		mainDocumentPart.Document = new Document();
		Body body = mainDocumentPart.Document.AppendChild(new Body());
		Paragraph paragraph = new Paragraph();
		Run run = new Run();
		run.AppendChild(new RunProperties
		{
			Bold = new Bold(),
			FontSize = new FontSize
			{
				Val = "48"
			}
		});
		run.AppendChild(new Text(title));
		paragraph.AppendChild(run);
		body.AppendChild(paragraph);
		body.AppendChild(new Paragraph());
		foreach (var section in sections)
		{
			string item = section.Heading;
			string item2 = section.Content;
			int item3 = section.Level;
			Paragraph paragraph2 = new Paragraph();
			Run run2 = new Run();
			run2.AppendChild(new RunProperties
			{
				Bold = new Bold(),
				FontSize = new FontSize
				{
					Val = ((item3 <= 1) ? "32" : "28")
				},
				Color = new Color
				{
					Val = "2B579A"
				}
			});
			run2.AppendChild(new Text(item));
			paragraph2.AppendChild(run2);
			body.AppendChild(paragraph2);
			string[] array = StripHtmlTags(item2).Split('\n', StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				Paragraph paragraph3 = new Paragraph();
				Run run3 = new Run();
				run3.AppendChild(new Text(text.Trim())
				{
					Space = SpaceProcessingModeValues.Preserve
				});
				paragraph3.AppendChild(run3);
				body.AppendChild(paragraph3);
			}
			body.AppendChild(new Paragraph());
		}
		return "  ✓ DOCX 조립 완료";
	}

	private string AssembleMarkdown(string path, string title, List<(string Heading, string Content, int Level)> sections)
	{
		StringBuilder stringBuilder = new StringBuilder();
		StringBuilder stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder3 = stringBuilder2;
		StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
		handler.AppendLiteral("# ");
		handler.AppendFormatted(title);
		stringBuilder3.AppendLine(ref handler);
		stringBuilder.AppendLine();
		stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder4 = stringBuilder2;
		handler = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder2);
		handler.AppendLiteral("*작성일: ");
		handler.AppendFormatted(DateTime.Now, "yyyy-MM-dd");
		handler.AppendLiteral("*");
		stringBuilder4.AppendLine(ref handler);
		stringBuilder.AppendLine();
		if (sections.Count > 1)
		{
			stringBuilder.AppendLine("## 목차");
			stringBuilder.AppendLine();
			foreach (var section in sections)
			{
				string item = section.Heading;
				string value = item.Replace(" ", "-").ToLowerInvariant();
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder5 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(7, 2, stringBuilder2);
				handler.AppendLiteral("- [");
				handler.AppendFormatted(item);
				handler.AppendLiteral("](#");
				handler.AppendFormatted(value);
				handler.AppendLiteral(")");
				stringBuilder5.AppendLine(ref handler);
			}
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("---");
			stringBuilder.AppendLine();
		}
		foreach (var section2 in sections)
		{
			string item2 = section2.Heading;
			string item3 = section2.Content;
			int item4 = section2.Level;
			string value2 = ((item4 <= 1) ? "##" : "###");
			stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder6 = stringBuilder2;
			handler = new StringBuilder.AppendInterpolatedStringHandler(1, 2, stringBuilder2);
			handler.AppendFormatted(value2);
			handler.AppendLiteral(" ");
			handler.AppendFormatted(item2);
			stringBuilder6.AppendLine(ref handler);
			stringBuilder.AppendLine();
			stringBuilder.AppendLine(StripHtmlTags(item3));
			stringBuilder.AppendLine();
		}
		File.WriteAllText(path, stringBuilder.ToString(), Encoding.UTF8);
		return "  ✓ Markdown 조립 완료";
	}

	private static int EstimateWordCount(string text)
	{
		if (string.IsNullOrWhiteSpace(text))
		{
			return 0;
		}
		string source = StripHtmlTags(text);
		int num = source.Count((char c) => c == ' ');
		int num2 = source.Count((char c) => c >= '가' && c <= '힣');
		return num + 1 + num2 / 3;
	}

	private static string StripHtmlTags(string html)
	{
		if (string.IsNullOrEmpty(html))
		{
			return "";
		}
		return Regex.Replace(html, "<[^>]+>", " ").Replace("&nbsp;", " ").Replace("&amp;", "&")
			.Replace("&lt;", "<")
			.Replace("&gt;", ">")
			.Replace("  ", " ")
			.Trim();
	}

	private static List<string> ValidateBasic(string html)
	{
		List<string> list = new List<string>();
		if (html.Length < 500)
		{
			list.Add("문서 내용이 매우 짧습니다 (500자 미만)");
		}
		Regex regex = new Regex("<h[23][^>]*>[^<]+</h[23]>\\s*<div class=\"section-content\">\\s*</div>", RegexOptions.IgnoreCase);
		MatchCollection matchCollection = regex.Matches(html);
		if (matchCollection.Count > 0)
		{
			list.Add($"빈 섹션 {matchCollection.Count}개 발견");
		}
		if (html.Contains("[TODO]", StringComparison.OrdinalIgnoreCase) || html.Contains("[PLACEHOLDER]", StringComparison.OrdinalIgnoreCase) || html.Contains("Lorem ipsum", StringComparison.OrdinalIgnoreCase))
		{
			list.Add("플레이스홀더 텍스트가 남아있습니다");
		}
		return list;
	}

	private static string Escape(string text)
	{
		return text.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;");
	}
}
