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

namespace AxCopilot.Services.Agent;

/// <summary>
/// HTML (.html) 보고서를 생성하는 내장 스킬.
/// 테마 무드(mood)를 선택하면 TemplateService에서 해당 CSS를 가져와 적용합니다.
/// TOC, 커버 페이지, 섹션 번호 등 고급 문서 기능을 지원합니다.
/// </summary>
public class HtmlSkill : IAgentTool
{
    public string Name => "html_create";
    public string Description => "Create a styled HTML (.html) document with rich formatting. " +
        "Supports: table of contents (toc), cover page, callouts (.callout-info/warning/tip/danger), " +
        "badges (.badge-blue/green/red/yellow/purple), CSS bar charts (.chart-bar), " +
        "progress bars (.progress), timelines (.timeline), grid layouts (.grid-2/3/4), " +
        "and auto section numbering. " +
        "Available moods: modern, professional, creative, minimal, elegant, dark, colorful, corporate, magazine, dashboard.";

    public ToolParameterSchema Parameters => new()
    {
        Properties = new()
        {
            ["path"] = new() { Type = "string", Description = "Output file path (.html). Relative to work folder." },
            ["title"] = new() { Type = "string", Description = "Document title (shown in browser tab and header)" },
            ["body"] = new() { Type = "string", Description = "HTML body content. Use semantic tags: h2/h3 for sections, " +
                "div.callout-info/warning/tip/danger for callouts, span.badge-blue/green/red for badges, " +
                "div.chart-bar>div.bar-item for charts, div.grid-2/3/4 for grid layouts, " +
                "div.timeline>div.timeline-item for timelines, div.progress for progress bars." },
            ["mood"] = new() { Type = "string", Description = "Design template mood: modern, professional, creative, minimal, elegant, dark, colorful, corporate, magazine, dashboard. Default: modern" },
            ["style"] = new() { Type = "string", Description = "Optional additional CSS. Appended after mood+shared CSS." },
            ["toc"] = new() { Type = "boolean", Description = "Auto-generate table of contents from h2/h3 headings. Default: false" },
            ["numbered"] = new() { Type = "boolean", Description = "Auto-number h2/h3 sections (1., 1-1., etc). Default: false" },
            ["cover"] = new()
            {
                Type = "object",
                Description = "Cover page config: {\"title\": \"...\", \"subtitle\": \"...\", \"author\": \"...\", \"date\": \"...\", \"gradient\": \"#hex1,#hex2\"}. Omit to skip cover page."
            },
        },
        Required = ["path", "title", "body"]
    };

    public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
    {
        var path = args.GetProperty("path").GetString() ?? "";
        var title = args.GetProperty("title").GetString() ?? "Report";
        var body = args.GetProperty("body").GetString() ?? "";
        var customStyle = args.TryGetProperty("style", out var s) ? s.GetString() : null;
        var mood = args.TryGetProperty("mood", out var m) ? m.GetString() ?? "modern" : "modern";
        var useToc = args.TryGetProperty("toc", out var tocVal) && tocVal.GetBoolean();
        var useNumbered = args.TryGetProperty("numbered", out var numVal) && numVal.GetBoolean();
        var hasCover = args.TryGetProperty("cover", out var coverVal) && coverVal.ValueKind == JsonValueKind.Object;

        var fullPath = FileReadTool.ResolvePath(path, context.WorkFolder);
        if (context.ActiveTab == "Cowork") fullPath = AgentContext.EnsureTimestampedPath(fullPath);
        if (!fullPath.EndsWith(".html", StringComparison.OrdinalIgnoreCase) &&
            !fullPath.EndsWith(".htm", StringComparison.OrdinalIgnoreCase))
            fullPath += ".html";

        if (!context.IsPathAllowed(fullPath))
            return ToolResult.Fail($"경로 접근 차단: {fullPath}");

        if (!await context.CheckWritePermissionAsync(Name, fullPath))
            return ToolResult.Fail($"쓰기 권한 거부: {fullPath}");

        try
        {
            var dir = Path.GetDirectoryName(fullPath);
            if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir);

            // 스타일 결정: mood CSS + shared CSS + custom
            var style = TemplateService.GetCss(mood);
            if (!string.IsNullOrEmpty(customStyle))
                style += "\n" + customStyle;

            var moodInfo = TemplateService.GetMood(mood);
            var moodLabel = moodInfo != null ? $" · {moodInfo.Icon} {moodInfo.Label}" : "";

            // 섹션 번호 자동 부여 — h2, h3에 class="numbered" 추가
            if (useNumbered)
                body = AddNumberedClass(body);

            // h2/h3에서 id 속성 자동 부여 (TOC 앵커용)
            body = EnsureHeadingIds(body);

            // TOC 생성
            var tocHtml = useToc ? GenerateToc(body) : "";

            // 커버 페이지 생성
            var coverHtml = hasCover ? GenerateCover(coverVal, title) : "";

            var sb = new StringBuilder();
            sb.AppendLine("<!DOCTYPE html>");
            sb.AppendLine("<html lang=\"ko\">");
            sb.AppendLine("<head>");
            sb.AppendLine("<meta charset=\"UTF-8\">");
            sb.AppendLine("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">");
            sb.AppendLine($"<title>{Escape(title)}</title>");
            sb.AppendLine($"<style>{style}</style>");
            sb.AppendLine("</head>");
            sb.AppendLine("<body>");
            sb.AppendLine("<div class=\"container\">");

            // 커버 페이지
            if (!string.IsNullOrEmpty(coverHtml))
            {
                sb.AppendLine(coverHtml);
            }
            else
            {
                // 커버가 없으면 기존 방식의 제목+메타
                sb.AppendLine($"<h1>{Escape(title)}</h1>");
                sb.AppendLine($"<div class=\"meta\">생성: {DateTime.Now:yyyy-MM-dd HH:mm} | AX Copilot{moodLabel}</div>");
            }

            // TOC
            if (!string.IsNullOrEmpty(tocHtml))
                sb.AppendLine(tocHtml);

            // 본문
            sb.AppendLine(body);

            sb.AppendLine("</div>");
            sb.AppendLine("</body>");
            sb.AppendLine("</html>");

            await File.WriteAllTextAsync(fullPath, sb.ToString(), Encoding.UTF8, ct);

            var features = new List<string>();
            if (useToc) features.Add("목차");
            if (useNumbered) features.Add("섹션번호");
            if (hasCover) features.Add("커버페이지");
            var featureStr = features.Count > 0 ? $" [{string.Join(", ", features)}]" : "";

            return ToolResult.Ok(
                $"HTML 문서 생성 완료: {fullPath} (디자인: {mood}{featureStr})",
                fullPath);
        }
        catch (Exception ex)
        {
            return ToolResult.Fail($"HTML 생성 실패: {ex.Message}");
        }
    }

    /// <summary>h2, h3 태그에 id 속성이 없으면 자동 부여</summary>
    private static string EnsureHeadingIds(string html)
    {
        int counter = 0;
        return Regex.Replace(html, @"<(h[23])(\s[^>]*)?>", match =>
        {
            var tag = match.Groups[1].Value;
            var attrs = match.Groups[2].Value;
            counter++;

            // 이미 id가 있으면 그대로
            if (attrs.Contains("id=", StringComparison.OrdinalIgnoreCase))
                return match.Value;

            return $"<{tag}{attrs} id=\"section-{counter}\">";
        });
    }

    /// <summary>h2, h3에 class="numbered" 추가</summary>
    private static string AddNumberedClass(string html)
    {
        return Regex.Replace(html, @"<(h[23])(\s[^>]*)?>", match =>
        {
            var tag = match.Groups[1].Value;
            var attrs = match.Groups[2].Value;

            // 이미 numbered 클래스가 있으면 그대로
            if (attrs.Contains("numbered", StringComparison.OrdinalIgnoreCase))
                return match.Value;

            // 기존 class 속성에 추가
            if (Regex.IsMatch(attrs, @"class\s*=\s*""", RegexOptions.IgnoreCase))
                return Regex.Replace(match.Value, @"class\s*=\s*""", "class=\"numbered ");

            return $"<{tag}{attrs} class=\"numbered\">";
        });
    }

    /// <summary>body HTML에서 h2/h3을 파싱해 목차 HTML 생성</summary>
    private static string GenerateToc(string html)
    {
        var headings = Regex.Matches(html, @"<(h[23])[^>]*id=""([^""]+)""[^>]*>(.*?)</\1>",
            RegexOptions.IgnoreCase | RegexOptions.Singleline);

        if (headings.Count == 0) return "";

        var sb = new StringBuilder();
        sb.AppendLine("<nav class=\"toc\">");
        sb.AppendLine("<h2>📋 목차</h2>");
        sb.AppendLine("<ul>");

        foreach (Match h in headings)
        {
            var level = h.Groups[1].Value.ToLower();
            var id = h.Groups[2].Value;
            // 태그 내부 텍스트에서 HTML 태그 제거
            var text = Regex.Replace(h.Groups[3].Value, @"<[^>]+>", "").Trim();
            var cssClass = level == "h3" ? " class=\"toc-h3\"" : "";
            sb.AppendLine($"<li{cssClass}><a href=\"#{id}\">{text}</a></li>");
        }

        sb.AppendLine("</ul>");
        sb.AppendLine("</nav>");
        return sb.ToString();
    }

    /// <summary>cover 객체에서 커버 페이지 HTML 생성</summary>
    private static string GenerateCover(JsonElement cover, string fallbackTitle)
    {
        var coverTitle = cover.TryGetProperty("title", out var ct) ? ct.GetString() ?? fallbackTitle : fallbackTitle;
        var subtitle = cover.TryGetProperty("subtitle", out var sub) ? sub.GetString() ?? "" : "";
        var author = cover.TryGetProperty("author", out var auth) ? auth.GetString() ?? "" : "";
        var date = cover.TryGetProperty("date", out var dt) ? dt.GetString() ?? DateTime.Now.ToString("yyyy-MM-dd") : DateTime.Now.ToString("yyyy-MM-dd");
        var gradient = cover.TryGetProperty("gradient", out var grad) ? grad.GetString() : null;

        var styleAttr = "";
        if (!string.IsNullOrEmpty(gradient) && gradient.Contains(','))
        {
            var colors = gradient.Split(',');
            styleAttr = $" style=\"background: linear-gradient(135deg, {colors[0].Trim()} 0%, {colors[1].Trim()} 100%)\"";
        }

        var sb = new StringBuilder();
        sb.AppendLine($"<div class=\"cover-page\"{styleAttr}>");
        sb.AppendLine($"<h1>{Escape(coverTitle)}</h1>");
        if (!string.IsNullOrEmpty(subtitle))
            sb.AppendLine($"<div class=\"cover-subtitle\">{Escape(subtitle)}</div>");
        sb.AppendLine("<div class=\"cover-divider\"></div>");

        var metaParts = new List<string>();
        if (!string.IsNullOrEmpty(author)) metaParts.Add(author);
        metaParts.Add(date);
        metaParts.Add("AX Copilot");
        sb.AppendLine($"<div class=\"cover-meta\">{Escape(string.Join(" · ", metaParts))}</div>");

        sb.AppendLine("</div>");
        return sb.ToString();
    }

    private static string Escape(string s) =>
        s.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;");
}
