// Copyright 2026 OfficeCLI (https://OfficeCLI.AI)
// SPDX-License-Identifier: Apache-2.0

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using OfficeCli.Core;
using Drawing = DocumentFormat.OpenXml.Drawing;

namespace OfficeCli.Handlers;

public partial class PowerPointHandler
{
    // ==================== Speaker Notes helpers ====================

    private static string GetNotesText(NotesSlidePart notesPart)
    {
        var spTree = notesPart.NotesSlide?.CommonSlideData?.ShapeTree;
        if (spTree == null) return "";

        foreach (var shape in spTree.Elements<Shape>())
        {
            var ph = shape.NonVisualShapeProperties?.ApplicationNonVisualDrawingProperties
                ?.GetFirstChild<PlaceholderShape>();
            if (ph?.Index?.Value == 1) // body/notes placeholder
            {
                return string.Join("\n", shape.TextBody?.Elements<Drawing.Paragraph>()
                    .Select(p => string.Concat(p.Elements<Drawing.Run>().Select(r => r.Text?.Text ?? "")))
                    ?? Enumerable.Empty<string>());
            }
        }
        return "";
    }

    /// <summary>
    /// Walk the notes body placeholder's first run and mirror its run-level
    /// formatting onto the notes DocumentNode.Format dictionary. Required so
    /// that `Set /slide[N]/notes --prop bold=true color=#FF0000` is observable
    /// via `Get /slide[N]/notes` (round-trip parity with shape Get).
    /// </summary>
    private static void PopulateNotesFormat(NotesSlidePart notesPart, DocumentNode node)
    {
        var spTree = notesPart.NotesSlide?.CommonSlideData?.ShapeTree;
        if (spTree == null) return;
        Shape? notesShape = null;
        foreach (var shape in spTree.Elements<Shape>())
        {
            var ph = shape.NonVisualShapeProperties?.ApplicationNonVisualDrawingProperties
                ?.GetFirstChild<PlaceholderShape>();
            if (ph?.Index?.Value == 1) { notesShape = shape; break; }
        }
        if (notesShape == null) return;
        var firstRun = notesShape.TextBody?
            .Elements<Drawing.Paragraph>()
            .SelectMany(p => p.Elements<Drawing.Run>())
            .FirstOrDefault();
        if (firstRun == null) return;
        // Reuse RunToNode (Format-builder for runs) and merge its Format keys
        // into the notes node — skip `text` so we don't clobber the notes-level
        // text (concatenation of all runs across all paragraphs).
        var runNode = RunToNode(firstRun, node.Path + "/run[1]", notesPart);
        foreach (var kv in runNode.Format)
        {
            if (kv.Key == "text") continue;
            node.Format[kv.Key] = kv.Value;
        }
        // Reading direction (rtl) lives on the paragraph, not the run.
        var firstPara = notesShape.TextBody?.Elements<Drawing.Paragraph>().FirstOrDefault();
        if (firstPara?.ParagraphProperties?.RightToLeft?.Value == true)
            node.Format["direction"] = "rtl";
    }

    private static void SetNotesText(NotesSlidePart notesPart, string text)
    {
        var spTree = notesPart.NotesSlide?.CommonSlideData?.ShapeTree
            ?? throw new InvalidOperationException("Notes slide has no shape tree");

        // Find body placeholder (idx=1)
        Shape? notesShape = null;
        foreach (var shape in spTree.Elements<Shape>())
        {
            var ph = shape.NonVisualShapeProperties?.ApplicationNonVisualDrawingProperties
                ?.GetFirstChild<PlaceholderShape>();
            if (ph?.Index?.Value == 1)
            {
                notesShape = shape;
                break;
            }
        }

        if (notesShape == null)
        {
            notesShape = new Shape(
                new NonVisualShapeProperties(
                    new NonVisualDrawingProperties { Id = 3, Name = "Notes Placeholder 2" },
                    new NonVisualShapeDrawingProperties(),
                    new ApplicationNonVisualDrawingProperties(
                        new PlaceholderShape { Type = PlaceholderValues.Body, Index = 1 }
                    )
                ),
                new ShapeProperties(),
                new TextBody(new Drawing.BodyProperties(), new Drawing.ListStyle(), new Drawing.Paragraph())
            );
            spTree.AppendChild(notesShape);
        }

        var textBody = notesShape.TextBody
            ?? (notesShape.TextBody = new TextBody(new Drawing.BodyProperties(), new Drawing.ListStyle()));

        textBody.RemoveAllChildren<Drawing.Paragraph>();
        foreach (var line in text.Split('\n'))
        {
            textBody.AppendChild(new Drawing.Paragraph(
                new Drawing.Run(
                    new Drawing.RunProperties { Language = "en-US" },
                    new Drawing.Text { Text = line }
                )
            ));
        }

        notesPart.NotesSlide!.Save();
    }

    /// <summary>
    /// Apply reading direction (rtl/ltr) to the notes body shape on a notes
    /// slide. Mirrors the shape direction fix in PowerPointHandler.Add.Shape.cs:
    /// sets &lt;a:pPr rtl="1"/&gt; on every paragraph and rtlCol="1" on the
    /// shape's bodyPr. RTL notes are required for Arabic / Hebrew authors
    /// reviewing speaker notes.
    /// </summary>
    private static void ApplyNotesDirection(NotesSlidePart notesPart, string value)
    {
        var spTree = notesPart.NotesSlide?.CommonSlideData?.ShapeTree;
        if (spTree == null) return;
        Shape? notesShape = null;
        foreach (var shape in spTree.Elements<Shape>())
        {
            var ph = shape.NonVisualShapeProperties?.ApplicationNonVisualDrawingProperties
                ?.GetFirstChild<PlaceholderShape>();
            if (ph?.Index?.Value == 1)
            {
                notesShape = shape;
                break;
            }
        }
        if (notesShape == null) return;
        bool rtl = ParsePptDirectionRtl(value);
        foreach (var para in notesShape.TextBody?.Elements<Drawing.Paragraph>() ?? Enumerable.Empty<Drawing.Paragraph>())
        {
            var pProps = para.ParagraphProperties ?? (para.ParagraphProperties = new Drawing.ParagraphProperties());
            // Clear semantics: direction=ltr strips the rtl attribute.
            if (rtl) pProps.RightToLeft = true;
            else pProps.RightToLeft = null;
        }
        var bodyPr = notesShape.TextBody?.Elements<Drawing.BodyProperties>().FirstOrDefault();
        if (bodyPr != null)
        {
            if (rtl)
                bodyPr.SetAttribute(new DocumentFormat.OpenXml.OpenXmlAttribute("", "rtlCol", "", "1"));
            else
                bodyPr.RemoveAttribute("rtlCol", "");
        }
    }

    private static NotesSlidePart EnsureNotesSlidePart(SlidePart slidePart)
    {
        if (slidePart.NotesSlidePart != null) return slidePart.NotesSlidePart;

        var notesPart = slidePart.AddNewPart<NotesSlidePart>();
        notesPart.NotesSlide = new NotesSlide(
            new CommonSlideData(
                new ShapeTree(
                    new NonVisualGroupShapeProperties(
                        new NonVisualDrawingProperties { Id = 1, Name = "" },
                        new NonVisualGroupShapeDrawingProperties(),
                        new ApplicationNonVisualDrawingProperties()
                    ),
                    new GroupShapeProperties(new Drawing.TransformGroup()),
                    // Slide image placeholder (idx=0)
                    new Shape(
                        new NonVisualShapeProperties(
                            new NonVisualDrawingProperties { Id = 2, Name = "Slide Image Placeholder 1" },
                            new NonVisualShapeDrawingProperties(),
                            new ApplicationNonVisualDrawingProperties(
                                new PlaceholderShape { Type = PlaceholderValues.SlideImage, Index = 0 }
                            )
                        ),
                        new ShapeProperties(),
                        new TextBody(new Drawing.BodyProperties(), new Drawing.ListStyle(), new Drawing.Paragraph())
                    ),
                    // Notes body placeholder (idx=1)
                    new Shape(
                        new NonVisualShapeProperties(
                            new NonVisualDrawingProperties { Id = 3, Name = "Notes Placeholder 2" },
                            new NonVisualShapeDrawingProperties(),
                            new ApplicationNonVisualDrawingProperties(
                                new PlaceholderShape { Type = PlaceholderValues.Body, Index = 1 }
                            )
                        ),
                        new ShapeProperties(),
                        new TextBody(
                            new Drawing.BodyProperties(),
                            new Drawing.ListStyle(),
                            new Drawing.Paragraph()
                        )
                    )
                )
            )
        );
        notesPart.NotesSlide.Save();
        return notesPart;
    }
}
