using System.Text.Json;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

namespace AxCopilot.Services.Agent;

public partial class DocxSkill
{
    // ─── 문서 빌더 헬퍼 ──────────────────────────────────────────────────────

    // ═══════════════════════════════════════════════════
    //  제목/소제목/본문 단락 생성
    // ═══════════════════════════════════════════════════

    private static Paragraph CreateTitleParagraph(string text)
    {
        var para = new Paragraph();
        para.ParagraphProperties = new ParagraphProperties
        {
            Justification = new Justification { Val = JustificationValues.Center },
            SpacingBetweenLines = new SpacingBetweenLines { After = "100" },
        };
        var run = new Run(new Text(text));
        run.RunProperties = new RunProperties
        {
            Bold = new Bold(),
            FontSize = new FontSize { Val = "44" }, // 22pt
            Color = new Color { Val = "1F3864" },
        };
        para.Append(run);
        return para;
    }

    private static Paragraph CreateHeadingParagraph(string text, int level)
    {
        var para = new Paragraph();
        var fontSize = level <= 1 ? "32" : "26"; // 16pt / 13pt
        var color = level <= 1 ? "2E74B5" : "404040";

        para.ParagraphProperties = new ParagraphProperties
        {
            SpacingBetweenLines = new SpacingBetweenLines { Before = level <= 1 ? "360" : "240", After = "120" },
        };

        // 레벨1 소제목에 하단 테두리 추가
        if (level <= 1)
        {
            para.ParagraphProperties.ParagraphBorders = new ParagraphBorders(
                new BottomBorder { Val = BorderValues.Single, Size = 4, Color = "B4C6E7", Space = 1 });
        }

        var run = new Run(new Text(text));
        run.RunProperties = new RunProperties
        {
            Bold = new Bold(),
            FontSize = new FontSize { Val = fontSize },
            Color = new Color { Val = color },
        };
        para.Append(run);
        return para;
    }

    private static Paragraph CreateBodyParagraph(string text)
    {
        var para = new Paragraph();
        para.ParagraphProperties = new ParagraphProperties
        {
            SpacingBetweenLines = new SpacingBetweenLines { Line = "360" }, // 1.5배 줄간격
        };

        // 인라인 서식 파싱: **bold**, *italic*, `code`
        AppendFormattedRuns(para, text);
        return para;
    }

    /// <summary>**bold**, *italic*, `code` 인라인 서식을 Run으로 변환</summary>
    private static void AppendFormattedRuns(Paragraph para, string text)
    {
        // 패턴: **bold** | *italic* | `code` | 일반텍스트
        var regex = new System.Text.RegularExpressions.Regex(
            @"\*\*(.+?)\*\*|\*(.+?)\*|`(.+?)`");
        int lastIndex = 0;

        foreach (System.Text.RegularExpressions.Match match in regex.Matches(text))
        {
            // 매치 전 일반 텍스트
            if (match.Index > lastIndex)
                para.Append(CreateRun(text[lastIndex..match.Index]));

            if (match.Groups[1].Success) // **bold**
            {
                var run = CreateRun(match.Groups[1].Value);
                run.RunProperties ??= new RunProperties();
                run.RunProperties.Bold = new Bold();
                para.Append(run);
            }
            else if (match.Groups[2].Success) // *italic*
            {
                var run = CreateRun(match.Groups[2].Value);
                run.RunProperties ??= new RunProperties();
                run.RunProperties.Italic = new Italic();
                para.Append(run);
            }
            else if (match.Groups[3].Success) // `code`
            {
                var run = CreateRun(match.Groups[3].Value);
                run.RunProperties ??= new RunProperties();
                run.RunProperties.RunFonts = new RunFonts { Ascii = "Consolas", HighAnsi = "Consolas" };
                run.RunProperties.FontSize = new FontSize { Val = "20" };
                run.RunProperties.Shading = new Shading
                {
                    Val = ShadingPatternValues.Clear,
                    Fill = "F2F2F2",
                    Color = "auto"
                };
                para.Append(run);
            }

            lastIndex = match.Index + match.Length;
        }

        // 나머지 텍스트
        if (lastIndex < text.Length)
            para.Append(CreateRun(text[lastIndex..]));

        // 빈 텍스트인 경우 빈 Run 추가
        if (lastIndex == 0 && text.Length == 0)
            para.Append(CreateRun(""));
    }

    private static Run CreateRun(string text)
    {
        var run = new Run(new Text(text) { Space = SpaceProcessingModeValues.Preserve });
        run.RunProperties = new RunProperties
        {
            FontSize = new FontSize { Val = "22" }, // 11pt
        };
        return run;
    }

    // ═══════════════════════════════════════════════════
    //  테이블 생성
    // ═══════════════════════════════════════════════════

    private static Table CreateTable(JsonElement section)
    {
        var headers = section.TryGetProperty("headers", out var hArr) ? hArr : default;
        var rows = section.TryGetProperty("rows", out var rArr) ? rArr : default;
        var tableStyle = section.TryGetProperty("style", out var ts) ? ts.GetString() ?? "striped" : "striped";

        var table = new Table();

        // 테이블 속성 — 테두리 + 전체 너비
        var tblProps = new TableProperties(
            new TableBorders(
                new TopBorder { Val = BorderValues.Single, Size = 4, Color = "D9D9D9" },
                new BottomBorder { Val = BorderValues.Single, Size = 4, Color = "D9D9D9" },
                new LeftBorder { Val = BorderValues.Single, Size = 4, Color = "D9D9D9" },
                new RightBorder { Val = BorderValues.Single, Size = 4, Color = "D9D9D9" },
                new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4, Color = "D9D9D9" },
                new InsideVerticalBorder { Val = BorderValues.Single, Size = 4, Color = "D9D9D9" }
            ),
            new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct }
        );
        table.AppendChild(tblProps);

        // 헤더 행
        if (headers.ValueKind == JsonValueKind.Array)
        {
            var headerRow = new TableRow();
            foreach (var h in headers.EnumerateArray())
            {
                var cell = new TableCell();
                cell.TableCellProperties = new TableCellProperties
                {
                    Shading = new Shading { Val = ShadingPatternValues.Clear, Fill = "2E74B5", Color = "auto" },
                    TableCellVerticalAlignment = new TableCellVerticalAlignment { Val = TableVerticalAlignmentValues.Center },
                };
                var para = new Paragraph(new Run(new Text(h.GetString() ?? ""))
                {
                    RunProperties = new RunProperties
                    {
                        Bold = new Bold(),
                        FontSize = new FontSize { Val = "20" },
                        Color = new Color { Val = "FFFFFF" },
                    }
                });
                para.ParagraphProperties = new ParagraphProperties
                {
                    SpacingBetweenLines = new SpacingBetweenLines { Before = "40", After = "40" },
                };
                cell.Append(para);
                headerRow.Append(cell);
            }
            table.Append(headerRow);
        }

        // 데이터 행
        if (rows.ValueKind == JsonValueKind.Array)
        {
            int rowIdx = 0;
            foreach (var row in rows.EnumerateArray())
            {
                var dataRow = new TableRow();
                foreach (var cellVal in row.EnumerateArray())
                {
                    var cell = new TableCell();

                    // striped 스타일: 짝수행에 배경색
                    if (tableStyle == "striped" && rowIdx % 2 == 0)
                    {
                        cell.TableCellProperties = new TableCellProperties
                        {
                            Shading = new Shading { Val = ShadingPatternValues.Clear, Fill = "F2F7FB", Color = "auto" },
                        };
                    }

                    var para = new Paragraph(new Run(new Text(cellVal.ToString()) { Space = SpaceProcessingModeValues.Preserve })
                    {
                        RunProperties = new RunProperties { FontSize = new FontSize { Val = "20" } }
                    });
                    para.ParagraphProperties = new ParagraphProperties
                    {
                        SpacingBetweenLines = new SpacingBetweenLines { Before = "20", After = "20" },
                    };
                    cell.Append(para);
                    dataRow.Append(cell);
                }
                table.Append(dataRow);
                rowIdx++;
            }
        }

        return table;
    }

    // ═══════════════════════════════════════════════════
    //  리스트 (번호/불릿)
    // ═══════════════════════════════════════════════════

    private static void AppendList(Body body, JsonElement section)
    {
        var items = section.TryGetProperty("items", out var arr) ? arr : default;
        var listStyle = section.TryGetProperty("style", out var ls) ? ls.GetString() ?? "bullet" : "bullet";

        if (items.ValueKind != JsonValueKind.Array) return;

        int idx = 1;
        foreach (var item in items.EnumerateArray())
        {
            var text = item.GetString() ?? item.ToString();
            var prefix = listStyle == "number" ? $"{idx}. " : "• ";

            var para = new Paragraph();
            para.ParagraphProperties = new ParagraphProperties
            {
                Indentation = new Indentation { Left = "720" }, // 0.5 inch
                SpacingBetweenLines = new SpacingBetweenLines { Line = "320" },
            };

            var prefixRun = new Run(new Text(prefix) { Space = SpaceProcessingModeValues.Preserve });
            prefixRun.RunProperties = new RunProperties
            {
                FontSize = new FontSize { Val = "22" },
                Bold = listStyle == "number" ? new Bold() : null,
            };
            para.Append(prefixRun);

            var textRun = new Run(new Text(text) { Space = SpaceProcessingModeValues.Preserve });
            textRun.RunProperties = new RunProperties { FontSize = new FontSize { Val = "22" } };
            para.Append(textRun);

            body.Append(para);
            idx++;
        }
    }

    // ═══════════════════════════════════════════════════
    //  페이지 나누기
    // ═══════════════════════════════════════════════════

    private static Paragraph CreatePageBreak()
    {
        var para = new Paragraph();
        var run = new Run(new Break { Type = BreakValues.Page });
        para.Append(run);
        return para;
    }

    // ═══════════════════════════════════════════════════
    //  머리글/바닥글
    // ═══════════════════════════════════════════════════

    private static void AddHeaderFooter(MainDocumentPart mainPart, Body body,
        string? headerText, string? footerText, bool showPageNumbers)
    {
        // 머리글
        if (!string.IsNullOrEmpty(headerText))
        {
            var headerPart = mainPart.AddNewPart<HeaderPart>();
            var header = new Header();
            var para = new Paragraph(new Run(new Text(headerText))
            {
                RunProperties = new RunProperties
                {
                    FontSize = new FontSize { Val = "18" }, // 9pt
                    Color = new Color { Val = "808080" },
                }
            });
            para.ParagraphProperties = new ParagraphProperties
            {
                Justification = new Justification { Val = JustificationValues.Right },
            };
            header.Append(para);
            headerPart.Header = header;

            // SectionProperties에 머리글 연결
            var secProps = body.GetFirstChild<SectionProperties>() ?? body.AppendChild(new SectionProperties());
            secProps.Append(new HeaderReference
            {
                Type = HeaderFooterValues.Default,
                Id = mainPart.GetIdOfPart(headerPart)
            });
        }

        // 바닥글
        if (!string.IsNullOrEmpty(footerText) || showPageNumbers)
        {
            var footerPart = mainPart.AddNewPart<FooterPart>();
            var footer = new Footer();
            var para = new Paragraph();
            para.ParagraphProperties = new ParagraphProperties
            {
                Justification = new Justification { Val = JustificationValues.Center },
            };

            var displayText = footerText ?? "AX Copilot";

            if (showPageNumbers)
            {
                // 바닥글 텍스트 + 페이지 번호
                if (displayText.Contains("{page}"))
                {
                    var parts = displayText.Split("{page}");
                    para.Append(CreateFooterRun(parts[0]));
                    para.Append(CreatePageNumberRun());
                    if (parts.Length > 1)
                        para.Append(CreateFooterRun(parts[1]));
                }
                else
                {
                    para.Append(CreateFooterRun(displayText + " · "));
                    para.Append(CreatePageNumberRun());
                }
            }
            else
            {
                para.Append(CreateFooterRun(displayText));
            }

            footer.Append(para);
            footerPart.Footer = footer;

            var secProps = body.GetFirstChild<SectionProperties>() ?? body.AppendChild(new SectionProperties());
            secProps.Append(new FooterReference
            {
                Type = HeaderFooterValues.Default,
                Id = mainPart.GetIdOfPart(footerPart)
            });
        }
    }

    private static Run CreateFooterRun(string text) =>
        new(new Text(text) { Space = SpaceProcessingModeValues.Preserve })
        {
            RunProperties = new RunProperties
            {
                FontSize = new FontSize { Val = "16" },
                Color = new Color { Val = "999999" },
            }
        };

    private static Run CreatePageNumberRun()
    {
        var run = new Run();
        run.RunProperties = new RunProperties
        {
            FontSize = new FontSize { Val = "16" },
            Color = new Color { Val = "999999" },
        };
        run.Append(new FieldChar { FieldCharType = FieldCharValues.Begin });
        run.Append(new FieldCode(" PAGE ") { Space = SpaceProcessingModeValues.Preserve });
        run.Append(new FieldChar { FieldCharType = FieldCharValues.End });
        return run;
    }
}
