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

namespace AxCopilot.Services.Agent;

/// <summary>
/// 생성된 문서를 자동 검증하는 도구.
/// HTML/Markdown/텍스트 파일의 구조적 완성도, 날짜 정합성, 빈 섹션 등을 점검합니다.
/// </summary>
public class DocumentReviewTool : IAgentTool
{
    public string Name => "document_review";
    public string Description =>
        "Review a generated document for quality issues. " +
        "Checks: empty sections, placeholder text, date consistency, missing headings, broken HTML tags, " +
        "content completeness. Returns a structured review report with issues found and suggestions.";

    public ToolParameterSchema Parameters => new()
    {
        Properties = new()
        {
            ["path"] = new() { Type = "string", Description = "Path to the document to review" },
            ["expected_sections"] = new()
            {
                Type = "array",
                Description = "Optional list of expected section titles to verify presence",
                Items = new() { Type = "string" },
            },
        },
        Required = ["path"]
    };

    public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
    {
        if (!args.TryGetProperty("path", out var pathEl))
            return Task.FromResult(ToolResult.Fail("path가 필요합니다."));
        var path = pathEl.GetString() ?? "";
        var fullPath = FileReadTool.ResolvePath(path, context.WorkFolder);

        if (!context.IsPathAllowed(fullPath))
            return Task.FromResult(ToolResult.Fail($"경로 접근 차단: {fullPath}"));
        if (!File.Exists(fullPath))
            return Task.FromResult(ToolResult.Fail($"파일 없음: {fullPath}"));

        var content = File.ReadAllText(fullPath);
        var ext = Path.GetExtension(fullPath).ToLowerInvariant();
        var issues = new List<string>();
        var stats = new List<string>();

        // 기본 통계
        var lineCount = content.Split('\n').Length;
        var charCount = content.Length;
        stats.Add($"파일: {Path.GetFileName(fullPath)} ({charCount:N0}자, {lineCount}줄)");

        // 1. 빈 콘텐츠 검사
        if (string.IsNullOrWhiteSpace(content))
        {
            issues.Add("[CRITICAL] 파일 내용이 비어있습니다");
            return Task.FromResult(ToolResult.Ok(FormatReport(stats, issues, []), fullPath));
        }

        // 2. 플레이스홀더 텍스트 검사
        var placeholders = new[] { "TODO", "TBD", "FIXME", "Lorem ipsum", "[여기에", "[INSERT", "placeholder", "예시 텍스트" };
        foreach (var ph in placeholders)
        {
            if (content.Contains(ph, StringComparison.OrdinalIgnoreCase))
                issues.Add($"[WARNING] 플레이스홀더 텍스트 발견: \"{ph}\"");
        }

        // 3. 날짜 정합성 (미래 날짜, 너무 오래된 날짜)
        var datePattern = new Regex(@"\d{4}[-년.]\s*\d{1,2}[-월.]\s*\d{1,2}[일]?");
        foreach (Match m in datePattern.Matches(content))
        {
            var cleaned = Regex.Replace(m.Value, @"[년월일\s]", "-").TrimEnd('-');
            if (DateTime.TryParse(cleaned, out var dt))
            {
                if (dt > DateTime.Now.AddDays(365))
                    issues.Add($"[WARNING] 미래 날짜 감지: {m.Value}");
                else if (dt < DateTime.Now.AddYears(-50))
                    issues.Add($"[INFO] 매우 오래된 날짜: {m.Value}");
            }
        }

        // 4. HTML 전용 검사
        if (ext is ".html" or ".htm")
        {
            // 빈 섹션 (h2/h3 뒤에 내용 없이 바로 다음 h2/h3)
            var emptySection = Regex.Matches(content, @"<h[23][^>]*>.*?</h[23]>\s*<h[23]");
            if (emptySection.Count > 0)
                issues.Add($"[WARNING] 빈 섹션 {emptySection.Count}개 감지 (헤딩 뒤 내용 없음)");

            // 닫히지 않은 태그
            var openTags = Regex.Matches(content, @"<(table|div|section|article)\b[^/]*>").Count;
            var closeTags = Regex.Matches(content, @"</(table|div|section|article)>").Count;
            if (openTags != closeTags)
                issues.Add($"[WARNING] HTML 태그 불균형: 열림 {openTags}개, 닫힘 {closeTags}개");

            // 이미지 alt 텍스트 누락
            var imgNoAlt = Regex.Matches(content, @"<img\b(?![^>]*\balt\s*=)[^>]*>");
            if (imgNoAlt.Count > 0)
                issues.Add($"[INFO] alt 속성 없는 이미지 {imgNoAlt.Count}개");

            // 제목 태그 수
            var h1Count = Regex.Matches(content, @"<h1\b").Count;
            var h2Count = Regex.Matches(content, @"<h2\b").Count;
            stats.Add($"구조: h1={h1Count}, h2={h2Count}개 섹션");
        }

        // 5. 기대 섹션 검사
        if (args.TryGetProperty("expected_sections", out var sections) && sections.ValueKind == JsonValueKind.Array)
        {
            foreach (var sec in sections.EnumerateArray())
            {
                var title = sec.GetString() ?? "";
                if (!string.IsNullOrEmpty(title) && !content.Contains(title, StringComparison.OrdinalIgnoreCase))
                    issues.Add($"[MISSING] 기대 섹션 누락: \"{title}\"");
            }
        }

        // 6. 반복 텍스트 검사 (같은 문장 3회 이상 반복)
        var sentences = Regex.Split(content, @"[.!?。]\s+")
            .Where(s => s.Length > 20)
            .GroupBy(s => s.Trim())
            .Where(g => g.Count() >= 3);
        foreach (var dup in sentences.Take(3))
            issues.Add($"[WARNING] 반복 텍스트 ({dup.Count()}회): \"{dup.Key[..Math.Min(50, dup.Key.Length)]}...\"");

        var suggestions = new List<string>();
        if (issues.Count == 0)
            suggestions.Add("문서 검증 통과 — 구조적 이슈가 발견되지 않았습니다.");
        else
        {
            suggestions.Add($"총 {issues.Count}개 이슈 발견. 수정 후 다시 검증하세요.");
            if (issues.Any(i => i.Contains("플레이스홀더")))
                suggestions.Add("플레이스홀더를 실제 내용으로 교체하세요.");
            if (issues.Any(i => i.Contains("빈 섹션")))
                suggestions.Add("빈 섹션에 내용을 추가하거나 불필요한 헤딩을 제거하세요.");
        }

        return Task.FromResult(ToolResult.Ok(FormatReport(stats, issues, suggestions), fullPath));
    }

    private static string FormatReport(List<string> stats, List<string> issues, List<string> suggestions)
    {
        var sb = new System.Text.StringBuilder();
        sb.AppendLine("=== 문서 검증 보고서 ===\n");
        foreach (var s in stats) sb.AppendLine($"📊 {s}");
        sb.AppendLine();
        if (issues.Count == 0)
            sb.AppendLine("✅ 이슈 없음 — 문서가 정상입니다.");
        else
        {
            sb.AppendLine($"⚠ 발견된 이슈 ({issues.Count}건):");
            foreach (var i in issues) sb.AppendLine($"  {i}");
        }
        sb.AppendLine();
        foreach (var s in suggestions) sb.AppendLine($"💡 {s}");
        return sb.ToString();
    }
}
