using System.IO;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using Markdig;

namespace AxCopilot.Services.Agent;

/// <summary>
/// 문서 포맷 변환 도구.
/// Markdown → HTML, HTML → 텍스트, CSV → HTML 테이블 등 경량 변환을 수행합니다.
/// 복잡한 변환(DOCX↔HTML)은 원본 파일을 읽고 적절한 생성 스킬(docx_create, html_create)로
/// 재생성하도록 LLM에 안내합니다.
/// </summary>
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 => new()
    {
        Properties = new()
        {
            ["source"] = new() { Type = "string", Description = "Source file path to convert" },
            ["target"] = new() { Type = "string", Description = "Target output file path (extension determines format)" },
            ["mood"] = new() { Type = "string", Description = "Design mood for HTML output (default: modern). Only used for md→html conversion." },
        },
        Required = ["source", "target"]
    };

    public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
    {
        var source = args.GetProperty("source").GetString() ?? "";
        var target = args.GetProperty("target").GetString() ?? "";
        var mood = args.TryGetProperty("mood", out var m) ? m.GetString() ?? "modern" : "modern";

        var srcPath = FileReadTool.ResolvePath(source, context.WorkFolder);
        var 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("쓰기 권한이 거부되었습니다.");

        var srcExt = Path.GetExtension(srcPath).ToLowerInvariant();
        var tgtExt = Path.GetExtension(tgtPath).ToLowerInvariant();
        var convKey = $"{srcExt}→{tgtExt}";

        try
        {
            var srcContent = await File.ReadAllTextAsync(srcPath, ct);

            string result;
            switch (convKey)
            {
                case ".md→.html":
                    var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
                    var bodyHtml = Markdown.ToHtml(srcContent, pipeline);
                    var 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" or ".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 등)을 사용하세요.");
            }

            var dir = Path.GetDirectoryName(tgtPath);
            if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir);
            await File.WriteAllTextAsync(tgtPath, result, ct);

            var srcName = Path.GetFileName(srcPath);
            var 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)
    {
        // script/style 제거
        var cleaned = Regex.Replace(html, @"<(script|style)[^>]*>.*?</\1>", "", RegexOptions.Singleline | RegexOptions.IgnoreCase);
        // 줄바꿈 태그 처리
        cleaned = Regex.Replace(cleaned, @"<br\s*/?>", "\n", RegexOptions.IgnoreCase);
        cleaned = Regex.Replace(cleaned, @"</(p|div|h[1-6]|li|tr)>", "\n", RegexOptions.IgnoreCase);
        // 태그 제거
        cleaned = Regex.Replace(cleaned, @"<[^>]+>", "");
        // HTML 엔티티 디코딩
        cleaned = System.Net.WebUtility.HtmlDecode(cleaned);
        // 연속 빈줄 정리
        cleaned = Regex.Replace(cleaned, @"\n{3,}", "\n\n");
        return cleaned.Trim();
    }

    private static string StripMarkdown(string md)
    {
        var result = md;
        result = Regex.Replace(result, @"^#{1,6}\s+", "", RegexOptions.Multiline); // 헤딩
        result = Regex.Replace(result, @"\*\*(.+?)\*\*", "$1"); // 볼드
        result = Regex.Replace(result, @"\*(.+?)\*", "$1"); // 이탤릭
        result = Regex.Replace(result, @"`(.+?)`", "$1"); // 인라인 코드
        result = Regex.Replace(result, @"^\s*[-*+]\s+", "", RegexOptions.Multiline); // 리스트
        result = Regex.Replace(result, @"^\s*\d+\.\s+", "", RegexOptions.Multiline); // 번호 리스트
        result = Regex.Replace(result, @"\[(.+?)\]\(.+?\)", "$1"); // 링크
        return result.Trim();
    }

    private static string CsvToHtmlTable(string csv, string mood)
    {
        var lines = csv.Split('\n', StringSplitOptions.RemoveEmptyEntries);
        if (lines.Length == 0) return "<p>빈 CSV 파일</p>";

        var cssStr = TemplateService.GetCss(mood);
        var sb = new StringBuilder();
        sb.AppendLine("<!DOCTYPE html>\n<html lang=\"ko\">\n<head>\n<meta charset=\"UTF-8\"/>");
        sb.AppendLine($"<style>{cssStr}</style>\n</head>\n<body>\n<div class=\"container\">");
        sb.AppendLine("<table><thead><tr>");

        var headers = ParseCsvLine(lines[0]);
        foreach (var h in headers) sb.Append($"<th>{System.Net.WebUtility.HtmlEncode(h)}</th>");
        sb.AppendLine("</tr></thead><tbody>");

        for (int i = 1; i < Math.Min(lines.Length, 1001); i++)
        {
            var vals = ParseCsvLine(lines[i]);
            sb.Append("<tr>");
            foreach (var v in vals) sb.Append($"<td>{System.Net.WebUtility.HtmlEncode(v)}</td>");
            sb.AppendLine("</tr>");
        }

        sb.AppendLine("</tbody></table>\n</div>\n</body>\n</html>");
        return sb.ToString();
    }

    private static string[] ParseCsvLine(string line)
    {
        var fields = new List<string>();
        var current = new StringBuilder();
        bool inQuotes = false;
        for (int i = 0; i < line.Length; i++)
        {
            var c = line[i];
            if (inQuotes)
            {
                if (c == '"' && i + 1 < line.Length && line[i + 1] == '"') { current.Append('"'); i++; }
                else if (c == '"') inQuotes = false;
                else current.Append(c);
            }
            else
            {
                if (c == '"') inQuotes = true;
                else if (c == ',') { fields.Add(current.ToString()); current.Clear(); }
                else current.Append(c);
            }
        }
        fields.Add(current.ToString());
        return fields.ToArray();
    }
}
