using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows.Documents;
using System.Windows.Media;

namespace ChatController.Core
{
    public static class FlowDocumentExtensions
    {
        private static IEnumerable<TextElement> GetRunsAndParagraphs(FlowDocument doc)
        {
            for (var position = doc.ContentStart; !(position is null) && position.CompareTo(doc.ContentEnd) <= 0; position = position.GetNextContextPosition(LogicalDirection.Forward))
            {
                if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd)
                {
                    switch (position.Parent)
                    {
                        case Run run:
                            yield return run;
                            break;
                        case Paragraph paragraph:
                            yield return paragraph;
                            break;
                    }
                }
            }
        }

        public static FormattedText GetFormattedText(this FlowDocument flowDocument)
        {
            if (flowDocument is null)
            {
                throw new ArgumentNullException(nameof(flowDocument));
            }

            var output = new FormattedText(GetText(flowDocument), CultureInfo.CurrentCulture, flowDocument.FlowDirection, new Typeface(flowDocument.FontFamily, flowDocument.FontStyle, flowDocument.FontWeight, flowDocument.FontStretch), flowDocument.FontSize, flowDocument.Foreground);

            var offset = 0;

            foreach (var textElement in GetRunsAndParagraphs(flowDocument))
            {
                if (textElement is Run run)
                {
                    var count = run.Text.Length;

                    output.SetFontFamily(run.FontFamily, offset, count);
                    output.SetFontStyle(run.FontStyle, offset, count);
                    output.SetFontWeight(run.FontWeight, offset, count);
                    output.SetFontSize(run.FontSize, offset, count);
                    output.SetForegroundBrush(run.Foreground, offset, count);
                    output.SetFontStretch(run.FontStretch, offset, count);
                    output.SetTextDecorations(run.TextDecorations, offset, count);

                    offset += count;
                }
                else
                {
                    offset += Environment.NewLine.Length;
                }
            }

            return output;
        }

        private static string GetText(FlowDocument flowDocument)
        {
            var stringBuilder = new StringBuilder();

            foreach (var textElement in GetRunsAndParagraphs(flowDocument))
            {
                stringBuilder.Append(!(textElement is Run run) ? Environment.NewLine : run.Text);
            }

            return stringBuilder.ToString();
        }
    }
}
