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

namespace AxCopilot.Services.Agent;

/// <summary>
/// 문서 개요(Outline)를 구조화된 JSON으로 생성하는 도구.
/// - 멀티패스(고품질) ON : 개요만 반환 → LLM이 섹션별로 상세 작성 → document_assemble로 조립
/// - 멀티패스(고품질) OFF: 개요 + 기본 문서를 즉시 로컬 파일로 저장 (LLM 호출 최소)
/// </summary>
public partial class DocumentPlannerTool : IAgentTool
{
    private static bool IsMultiPassEnabled(AgentContext context)
    {
        return context.Llm?.EnableMultiPassDocument ?? false;
    }

    private static string GetFolderDataUsage(AgentContext context)
    {
        return context.Llm?.FolderDataUsage ?? "none";
    }

    public string Name => "document_plan";
    public string Description =>
        "Create a structured document outline/plan and optionally generate the document file immediately. " +
        "Use this BEFORE generating long documents (3+ pages). " +
        "When multi-pass mode is OFF, this tool directly creates and saves a document file with section headings and key points. " +
        "When multi-pass mode is ON, returns a plan for section-by-section writing via document_assemble.";

    public ToolParameterSchema Parameters => new()
    {
        Properties = new()
        {
            ["topic"] = new()
            {
                Type = "string",
                Description = "Document topic or full user request describing what the document should cover."
            },
            ["document_type"] = new()
            {
                Type = "string",
                Description = "Type of document: report, proposal, analysis, manual, minutes, presentation, guide. Default: report",
                Enum = ["report", "proposal", "analysis", "manual", "minutes", "presentation", "guide"]
            },
            ["target_pages"] = new()
            {
                Type = "integer",
                Description = "Target number of pages (1 page ≈ 500 words). Default: 5"
            },
            ["format"] = new()
            {
                Type = "string",
                Description = "Output document format: html, docx, markdown. Default: html",
                Enum = ["html", "docx", "markdown"]
            },
            ["sections_hint"] = new()
            {
                Type = "string",
                Description = "Optional hint for desired sections/structure (e.g. '서론, 현황분석, 문제점, 개선방안, 결론')"
            },
            ["reference_summary"] = new()
            {
                Type = "string",
                Description = "Optional summary of reference data already read via file_read (to incorporate into plan)"
            },
        },
        Required = ["topic"]
    };

    public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
    {
        var topic = args.GetProperty("topic").GetString() ?? "";
        var docType = args.TryGetProperty("document_type", out var dt) ? dt.GetString() ?? "report" : "report";
        var targetPages = args.TryGetProperty("target_pages", out var tp) ? tp.GetInt32() : 5;
        var format = args.TryGetProperty("format", out var fmt) ? fmt.GetString() ?? "html" : "html";
        var sectionsHint = args.TryGetProperty("sections_hint", out var sh) ? sh.GetString() ?? "" : "";
        var refSummary = args.TryGetProperty("reference_summary", out var rs) ? rs.GetString() ?? "" : "";

        if (string.IsNullOrWhiteSpace(topic))
            return Task.FromResult(ToolResult.Fail("topic이 비어있습니다."));

        if (targetPages < 1) targetPages = 1;
        if (targetPages > 50) targetPages = 50;

        var highQuality = IsMultiPassEnabled(context);
        var folderDataUsage = GetFolderDataUsage(context);

        // 고품질 모드: 목표 페이지와 단어 수를 1.5배 확장
        var effectivePages = highQuality ? (int)Math.Ceiling(targetPages * 1.5) : targetPages;
        var totalWords = effectivePages * 500;

        var sections = BuildSections(docType, effectivePages, sectionsHint, refSummary);
        DistributeWordCount(sections, totalWords);

        // 폴더 데이터 활용 모드: 먼저 파일을 읽어야 하므로 별도 처리
        if (folderDataUsage is "active" or "passive")
            return ExecuteSinglePassWithData(topic, docType, format, effectivePages, totalWords, sections, folderDataUsage, refSummary);

        // 일반/고품질 모드 모두 동일 구조:
        // 개요 반환 + document_assemble 즉시 호출 지시
        return ExecuteWithAssembleInstructions(topic, docType, format, effectivePages, totalWords, sections, highQuality);
    }

    // ─── 통합: 포맷별 body 골격 생성 + 즉시 호출 가능한 도구 파라미터 제시 ──────

    private Task<ToolResult> ExecuteWithAssembleInstructions(string topic, string docType, string format,
        int targetPages, int totalWords, List<SectionPlan> sections, bool highQuality)
    {
        var safeTitle = SanitizeFileName(topic);
        var ext = format switch { "docx" => ".docx", "markdown" => ".md", _ => ".html" };
        var suggestedFileName = $"{safeTitle}{ext}";
        var label = highQuality ? "[고품질]" : "[표준]";

        switch (format)
        {
            case "markdown":
                return ExecuteWithMarkdownScaffold(topic, suggestedFileName, sections, targetPages, totalWords, label);
            case "docx":
                return ExecuteWithDocxScaffold(topic, suggestedFileName, sections, targetPages, totalWords, label);
            default: // html
                return ExecuteWithHtmlScaffold(topic, suggestedFileName, sections, targetPages, totalWords, label);
        }
    }

    /// <summary>html_create 즉시 호출 가능한 body 골격 반환. 섹션 구조만 고정하고 내부 시각화는 LLM이 자유롭게 선택.</summary>
    private Task<ToolResult> ExecuteWithHtmlScaffold(string topic, string fileName,
        List<SectionPlan> sections, int targetPages, int totalWords, string label)
    {
        var bodySb = new StringBuilder();
        foreach (var s in sections)
        {
            // 키포인트 내용을 분석해 적합한 HTML 요소를 제안 (강제 아님)
            var elementHints = SuggestHtmlElements(s.KeyPoints);

            bodySb.AppendLine($"<h2>{Escape(s.Heading)}</h2>");
            bodySb.AppendLine($"<!-- 목표 {s.TargetWords}단어 | 핵심: {string.Join(", ", s.KeyPoints)}");
            bodySb.AppendLine($"     활용 가능 요소(내용에 맞게 자유 선택): {elementHints} -->");
            // 섹션 내부는 완전히 비워둠 — LLM이 내용과 구조를 모두 결정
            bodySb.AppendLine();
        }

        var output = new StringBuilder();
        output.AppendLine($"📋 문서 개요 생성 완료 {label} ({sections.Count}개 섹션, {targetPages}페이지/{totalWords}단어)");
        output.AppendLine();
        output.AppendLine("## 즉시 실행: html_create 호출");
        output.AppendLine($"path: \"{fileName}\"");
        output.AppendLine($"title: \"{topic}\"");
        output.AppendLine("toc: true, numbered: true, mood: \"professional\"");
        output.AppendLine($"cover: {{\"title\": \"{topic}\", \"author\": \"AX Copilot Agent\"}}");
        output.AppendLine();
        output.AppendLine("body에 아래 섹션 구조를 기반으로 각 섹션의 내용과 시각화를 자유롭게 작성하세요:");
        output.AppendLine("(주석의 '활용 가능 요소'는 참고용이며, 내용에 맞게 다른 요소를 써도 됩니다)");
        output.AppendLine();
        output.AppendLine("--- body 시작 ---");
        output.Append(bodySb);
        output.AppendLine("--- body 끝 ---");
        output.AppendLine();
        output.AppendLine("⚠ html_create를 지금 즉시 호출하세요. 모든 섹션에 충분한 실제 내용을 작성하세요.");

        return Task.FromResult(ToolResult.Ok(output.ToString()));
    }

    /// <summary>키포인트 키워드를 분석해 적합한 HTML 시각화 요소를 제안합니다.</summary>
    private static string SuggestHtmlElements(List<string> keyPoints)
    {
        var joined = string.Join(" ", keyPoints).ToLowerInvariant();
        var hints = new List<string>();

        // 숫자/통계/비교 데이터 → 테이블 또는 차트
        if (ContainsAny(joined, "매출", "실적", "통계", "수치", "비교", "현황", "지표", "점유율", "비율", "순위", "성과"))
        {
            hints.Add("table(데이터 정리)");
            hints.Add("div.chart-bar(수치 시각화)");
        }
        // SWOT/강약점/리스크 → 그리드 + 콜아웃
        if (ContainsAny(joined, "강점", "약점", "기회", "위협", "swot", "리스크", "문제점", "장점", "단점"))
        {
            hints.Add("div.grid-2(항목 대비)");
            hints.Add("callout-warning/callout-tip");
        }
        // 전략/제안/방향 → 콜아웃 + 배지
        if (ContainsAny(joined, "전략", "제안", "방안", "계획", "방향", "로드맵", "목표"))
        {
            hints.Add("callout-info(핵심 전략)");
            hints.Add("span.badge-blue/green(구분 배지)");
        }
        // 일정/단계/프로세스 → 타임라인
        if (ContainsAny(joined, "일정", "단계", "절차", "프로세스", "과정", "순서", "연혁", "역사"))
            hints.Add("div.timeline(단계/일정)");
        // 진행률/달성도 → 진행 바
        if (ContainsAny(joined, "달성", "진행", "완료", "목표 대비", "진척"))
            hints.Add("div.progress(달성률)");
        // 카드형 항목 나열
        if (ContainsAny(joined, "종류", "유형", "분류", "구성", "항목", "요소", "구분"))
            hints.Add("div.grid-3.card(항목 카드)");
        // 인용/핵심 메시지
        if (ContainsAny(joined, "핵심", "요약", "결론", "시사점", "포인트"))
            hints.Add("blockquote(핵심 메시지)");

        // 기본 (항상 포함)
        hints.Add("p/ul/ol(일반 서술)");

        // 중복 제거, 최대 4개
        return string.Join(" | ", hints.Distinct().Take(4));
    }

    private static bool ContainsAny(string text, params string[] keywords)
        => keywords.Any(k => text.Contains(k));

    /// <summary>document_assemble 즉시 호출 가능한 sections 골격 반환 (docx용).</summary>
    private Task<ToolResult> ExecuteWithDocxScaffold(string topic, string fileName,
        List<SectionPlan> sections, int targetPages, int totalWords, string label)
    {
        var sectionsTemplate = sections.Select(s => new
        {
            heading = s.Heading,
            content = $"[{s.Heading} 내용을 {s.TargetWords}단어 이상으로 작성. 핵심 항목: {string.Join(", ", s.KeyPoints)}]",
            level   = s.Level,
        });
        var json = JsonSerializer.Serialize(new
        {
            path    = fileName,
            title   = topic,
            format  = "docx",
            cover_subtitle = "AX Copilot Agent",
            sections = sectionsTemplate,
        }, _jsonOptions);

        var output = new StringBuilder();
        output.AppendLine($"📋 문서 개요 생성 완료 {label} ({sections.Count}개 섹션, {targetPages}페이지/{totalWords}단어)");
        output.AppendLine("아래 document_assemble 파라미터에서 각 sections[].content의 [내용...] 부분을 실제 내용으로 채워서 즉시 호출하세요.");
        output.AppendLine();
        output.AppendLine("## 즉시 실행: document_assemble 호출 파라미터");
        output.AppendLine(json);
        output.AppendLine("⚠ 주의: 설명하지 말고 document_assemble 도구를 지금 즉시 호출하세요.");

        return Task.FromResult(ToolResult.Ok(output.ToString()));
    }

    /// <summary>html_create(markdown body) 즉시 호출 가능한 골격 반환.</summary>
    private Task<ToolResult> ExecuteWithMarkdownScaffold(string topic, string fileName,
        List<SectionPlan> sections, int targetPages, int totalWords, string label)
    {
        var mdSb = new StringBuilder();
        mdSb.AppendLine($"# {topic}");
        mdSb.AppendLine();
        mdSb.AppendLine($"*작성일: {DateTime.Now:yyyy-MM-dd}*");
        mdSb.AppendLine();
        foreach (var s in sections)
        {
            mdSb.AppendLine($"## {s.Heading}");
            mdSb.AppendLine();
            mdSb.AppendLine($"<!-- 목표 {s.TargetWords}단어 | 핵심: {string.Join(" / ", s.KeyPoints)} -->");
            mdSb.AppendLine($"[{s.Heading} 내용을 {s.TargetWords}단어 이상으로 상세히 작성하세요]");
            mdSb.AppendLine();
        }

        var output = new StringBuilder();
        output.AppendLine($"📋 문서 개요 생성 완료 {label} ({sections.Count}개 섹션, {targetPages}페이지/{totalWords}단어)");
        output.AppendLine("아래 file_write 파라미터에서 각 섹션의 [내용...] 부분을 실제 내용으로 채워서 즉시 호출하세요.");
        output.AppendLine();
        output.AppendLine("## 즉시 실행: file_write 호출");
        output.AppendLine($"- path: \"{fileName}\"");
        output.AppendLine("- content (각 [내용...] 부분을 실제 내용으로 교체):");
        output.AppendLine(mdSb.ToString());
        output.AppendLine("⚠ 주의: 설명하지 말고 file_write 도구를 지금 즉시 호출하세요. 모든 섹션에 실제 내용을 작성하세요.");

        return Task.FromResult(ToolResult.Ok(output.ToString()));
    }

    // ─── 싱글패스 + 폴더 데이터 활용: 개요 반환 + LLM이 데이터 읽고 직접 저장 ──

    private Task<ToolResult> ExecuteSinglePassWithData(string topic, string docType, string format,
        int targetPages, int totalWords, List<SectionPlan> sections, string folderDataUsage, string refSummary)
    {
        var ext = format switch { "docx" => ".docx", "markdown" => ".md", _ => ".html" };
        var createTool = format switch { "docx" => "docx_create", "markdown" => "file_write", _ => "html_create" };
        var safeTitle = SanitizeFileName(topic);
        var suggestedPath = $"{safeTitle}{ext}";

        // reference_summary가 이미 있으면 데이터 읽기 단계를 건너뛸 수 있음
        var hasRefData = !string.IsNullOrWhiteSpace(refSummary);

        var plan = new
        {
            topic,
            document_type = docType,
            format,
            target_pages = targetPages,
            estimated_total_words = totalWords,
            suggested_file_name = suggestedPath,
            sections,
            reference_data = hasRefData ? refSummary : null as string,
            instructions = new
            {
                mode = "single-pass-with-data",
                folder_data_usage = folderDataUsage,
                step1 = hasRefData
                    ? "Reference data is already provided above. Skip to step 3."
                    : "Use folder_map to scan the work folder, then use document_read to read RELEVANT files only.",
                step2 = hasRefData
                    ? "(skipped)"
                    : "Summarize the key findings from the folder documents relevant to the topic.",
                step3 = $"Write the COMPLETE document content covering ALL sections above, incorporating folder data.",
                step4 = $"Save the document using {createTool} with the path '{suggestedPath}'. " +
                         "Write ALL sections in a SINGLE tool call. Do NOT split into multiple calls.",
                note = "Minimize LLM calls. Read data → write complete document → save. Maximum 3 iterations."
            }
        };

        var json = JsonSerializer.Serialize(plan, _jsonOptions);

        var dataNote = hasRefData
            ? "참조 데이터가 이미 제공되었습니다. 바로 문서를 작성하세요."
            : $"폴더 데이터 활용 모드({folderDataUsage})가 활성화되어 있습니다. 먼저 관련 데이터를 읽은 후 문서를 작성하세요.";

        return Task.FromResult(ToolResult.Ok(
            $"📋 문서 개요가 생성되었습니다 [싱글패스+데이터활용] ({sections.Count}개 섹션, 목표 {targetPages}페이지/{totalWords}단어).\n" +
            $"{dataNote}\n" +
            $"작성 완료 후 {createTool}로 '{suggestedPath}' 파일에 저장하세요.\n\n{json}"));
    }

}
