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

namespace AxCopilot.Services.Agent;

/// <summary>
/// 긴 텍스트나 문서를 지정된 길이와 형식으로 요약하는 도구.
/// 텍스트를 청크 분할하여 단계적으로 요약합니다.
/// </summary>
public class TextSummarizeTool : IAgentTool
{
    public string Name => "text_summarize";
    public string Description =>
        "Summarize long text or documents into a specified length and format. " +
        "Supports: bullet points, paragraph, executive summary, technical summary. " +
        "For very long texts, automatically chunks and summarizes progressively. " +
        "Can summarize file contents or inline text.";

    public ToolParameterSchema Parameters => new()
    {
        Properties = new()
        {
            ["source"] = new()
            {
                Type = "string",
                Description = "Text to summarize, OR file path (if starts with '/' or contains '\\' or '.'). " +
                    "For files: supports .txt, .md, .html, .csv, .json, .log"
            },
            ["max_length"] = new()
            {
                Type = "integer",
                Description = "Maximum summary length in characters. Default: 500"
            },
            ["style"] = new()
            {
                Type = "string",
                Description = "Summary style: bullet (bullet points), paragraph (flowing text), " +
                    "executive (key conclusions + action items), technical (detailed with terminology). Default: bullet",
                Enum = ["bullet", "paragraph", "executive", "technical"]
            },
            ["language"] = new()
            {
                Type = "string",
                Description = "Output language: ko (Korean), en (English). Default: ko"
            },
            ["focus"] = new()
            {
                Type = "string",
                Description = "Optional focus area or keywords to emphasize in the summary."
            },
            ["sections"] = new()
            {
                Type = "boolean",
                Description = "If true, provide section-by-section summary instead of one overall summary. Default: false"
            },
        },
        Required = ["source"]
    };

    public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
    {
        var source = args.GetProperty("source").GetString() ?? "";
        var maxLength = args.TryGetProperty("max_length", out var mlEl) && mlEl.TryGetInt32(out var ml) ? ml : 500;
        var style = args.TryGetProperty("style", out var stEl) ? stEl.GetString() ?? "bullet" : "bullet";
        var language = args.TryGetProperty("language", out var langEl) ? langEl.GetString() ?? "ko" : "ko";
        var focus = args.TryGetProperty("focus", out var focEl) ? focEl.GetString() ?? "" : "";
        var bySections = args.TryGetProperty("sections", out var secEl) && secEl.GetBoolean();

        string text;

        // 파일 경로인지 확인
        if (LooksLikeFilePath(source))
        {
            var fullPath = FileReadTool.ResolvePath(source, context.WorkFolder);
            if (!context.IsPathAllowed(fullPath))
                return ToolResult.Fail($"경로 접근 차단: {fullPath}");
            if (!File.Exists(fullPath))
                return ToolResult.Fail($"파일 없음: {fullPath}");

            text = await File.ReadAllTextAsync(fullPath, ct);

            // HTML 태그 제거
            if (fullPath.EndsWith(".html", StringComparison.OrdinalIgnoreCase) ||
                fullPath.EndsWith(".htm", StringComparison.OrdinalIgnoreCase))
            {
                text = StripHtmlTags(text);
            }
        }
        else
        {
            text = source;
        }

        if (string.IsNullOrWhiteSpace(text))
            return ToolResult.Fail("요약할 텍스트가 비어있습니다.");

        // 텍스트 통계
        var charCount = text.Length;
        var lineCount = text.Split('\n').Length;
        var wordCount = EstimateWordCount(text);

        // 텍스트가 이미 충분히 짧으면 그대로 반환
        if (charCount <= maxLength)
            return ToolResult.Ok($"📝 텍스트가 이미 요약 기준 이하입니다 ({charCount}자).\n\n{text}");

        // 청크 분할 (매우 긴 텍스트용)
        var chunks = ChunkText(text, 3000);
        var chunkSummaries = new List<string>();

        foreach (var chunk in chunks)
        {
            var summary = ExtractKeyContent(chunk, maxLength / chunks.Count, style, focus);
            chunkSummaries.Add(summary);
        }

        // 최종 요약 구성
        var sb = new StringBuilder();
        sb.AppendLine($"📝 텍스트 요약 (원문: {charCount:N0}자, {lineCount}줄, ~{wordCount}단어)");
        sb.AppendLine();

        if (bySections && chunks.Count > 1)
        {
            for (int i = 0; i < chunkSummaries.Count; i++)
            {
                sb.AppendLine($"### 섹션 {i + 1}/{chunkSummaries.Count}");
                sb.AppendLine(chunkSummaries[i]);
                sb.AppendLine();
            }
        }
        else
        {
            var combined = string.Join("\n", chunkSummaries);
            sb.AppendLine(FormatSummary(combined, style, language, focus));
        }

        var result = sb.ToString();
        if (result.Length > maxLength + 500)
            result = result[..(maxLength + 500)] + "\n...[요약 길이 초과로 생략]";

        return ToolResult.Ok(result);
    }

    private static bool LooksLikeFilePath(string s)
    {
        if (string.IsNullOrEmpty(s)) return false;
        if (s.Contains('\\') || s.Contains('/')) return true;
        if (s.Length < 260 && System.Text.RegularExpressions.Regex.IsMatch(s, @"\.\w{1,5}$"))
            return true;
        return false;
    }

    private static string StripHtmlTags(string html)
    {
        var text = System.Text.RegularExpressions.Regex.Replace(html, @"<script[^>]*>.*?</script>", "",
            System.Text.RegularExpressions.RegexOptions.Singleline);
        text = System.Text.RegularExpressions.Regex.Replace(text, @"<style[^>]*>.*?</style>", "",
            System.Text.RegularExpressions.RegexOptions.Singleline);
        text = System.Text.RegularExpressions.Regex.Replace(text, @"<[^>]+>", " ");
        text = System.Net.WebUtility.HtmlDecode(text);
        return System.Text.RegularExpressions.Regex.Replace(text, @"\s+", " ").Trim();
    }

    private static int EstimateWordCount(string text)
    {
        var spaces = text.Count(c => c == ' ');
        var koreanChars = text.Count(c => c >= 0xAC00 && c <= 0xD7A3);
        return spaces + 1 + koreanChars / 3;
    }

    private static List<string> ChunkText(string text, int chunkSize)
    {
        var chunks = new List<string>();
        var lines = text.Split('\n');
        var currentChunk = new StringBuilder();

        foreach (var line in lines)
        {
            if (currentChunk.Length + line.Length > chunkSize && currentChunk.Length > 0)
            {
                chunks.Add(currentChunk.ToString());
                currentChunk.Clear();
            }
            currentChunk.AppendLine(line);
        }

        if (currentChunk.Length > 0)
            chunks.Add(currentChunk.ToString());

        return chunks;
    }

    private static string ExtractKeyContent(string text, int targetLength, string style, string focus)
    {
        // 텍스트에서 핵심 문장 추출 (간단한 추출 기반 요약)
        var sentences = System.Text.RegularExpressions.Regex.Split(text, @"(?<=[.!?。\n])\s+")
            .Where(s => s.Trim().Length > 10)
            .ToList();

        if (sentences.Count == 0) return text.Length > targetLength ? text[..targetLength] : text;

        // 중요도 점수 계산
        var scored = sentences.Select(s =>
        {
            double score = 0;
            // 길이 적정성 (너무 짧지도 길지도 않은 문장 선호)
            if (s.Length > 20 && s.Length < 200) score += 1;
            // 숫자 포함 (데이터/통계)
            if (System.Text.RegularExpressions.Regex.IsMatch(s, @"\d+")) score += 0.5;
            // 키워드 포함
            if (!string.IsNullOrEmpty(focus) && s.Contains(focus, StringComparison.OrdinalIgnoreCase)) score += 2;
            // 위치 가중치 (첫 문장, 마지막 문장 중요)
            var idx = sentences.IndexOf(s);
            if (idx == 0 || idx == sentences.Count - 1) score += 1;
            if (idx < 3) score += 0.5; // 앞쪽 문장 선호
            // 핵심 키워드
            if (s.Contains("결론") || s.Contains("요약") || s.Contains("핵심") ||
                s.Contains("중요") || s.Contains("결과") || s.Contains("therefore") ||
                s.Contains("conclusion") || s.Contains("key"))
                score += 1.5;

            return (Sentence: s.Trim(), Score: score);
        })
        .OrderByDescending(x => x.Score)
        .ToList();

        // 목표 길이에 맞게 문장 선택
        var selected = new List<string>();
        int currentLength = 0;
        foreach (var (sentence, _) in scored)
        {
            if (currentLength + sentence.Length > targetLength && selected.Count > 0) break;
            selected.Add(sentence);
            currentLength += sentence.Length;
        }

        // 원문 순서로 재정렬
        selected.Sort((a, b) => text.IndexOf(a).CompareTo(text.IndexOf(b)));

        return string.Join("\n", selected);
    }

    private static string FormatSummary(string content, string style, string language, string focus)
    {
        switch (style)
        {
            case "bullet":
                var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
                return string.Join("\n", lines.Select(l => l.StartsWith("•") || l.StartsWith("-") ? l : $"• {l}"));

            case "executive":
                var sb = new StringBuilder();
                sb.AppendLine("**핵심 요약**");
                sb.AppendLine(content);
                if (!string.IsNullOrEmpty(focus))
                    sb.AppendLine($"\n**주요 관심 영역 ({focus})**");
                return sb.ToString();

            case "technical":
                return $"**기술 요약**\n{content}";

            default: // paragraph
                return content.Replace("\n\n", "\n").Replace("\n", " ").Trim();
        }
    }
}
