using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;

namespace RenderDemo.Pages
{
    public class TextFormatterPage : UserControl
    {
        private TextLine _textLine;
        
        public TextFormatterPage()
        {
            this.InitializeComponent();
        }

        private void InitializeComponent()
        {
            AvaloniaXamlLoader.Load(this);
        }
        
        public override void Render(DrawingContext context)
        {
            _textLine?.Draw(context, new Point());
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            var defaultRunProperties = new GenericTextRunProperties(Typeface.Default, foregroundBrush: Brushes.Black,
                baselineAlignment: BaselineAlignment.Center);
            var paragraphProperties = new GenericTextParagraphProperties(defaultRunProperties);

            var control = new Button { Content = new TextBlock { Text = "ClickMe" } };
            
            Content = control;
            
            var textSource = new CustomTextSource(control, defaultRunProperties);

            control.Measure(Size.Infinity);

            _textLine =
                TextFormatter.Current.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties);
            
            return base.MeasureOverride(availableSize);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            var currentX = 0d;
            
            foreach (var textRun in _textLine.TextRuns)
            {
                if (textRun is ControlRun controlRun)
                {
                    controlRun.Control.Arrange(new Rect(new Point(currentX, 0), controlRun.Size));
                }

                if (textRun is DrawableTextRun drawableTextRun)
                {
                    currentX += drawableTextRun.Size.Width;
                }
            }
            
            return finalSize;
        }

        private class CustomTextSource : ITextSource
        {
            private readonly Control _control;
            private readonly TextRunProperties _defaultProperties;
            private readonly string _text = "<-Hello World->";

            public CustomTextSource(Control control, TextRunProperties defaultProperties)
            {
                _control = control;
                _defaultProperties = defaultProperties;
            }
            
            public TextRun? GetTextRun(int textSourceIndex)
            {
                if (textSourceIndex >= _text.Length * 2 + TextRun.DefaultTextSourceLength)
                {
                    return null;
                }

                if (textSourceIndex == _text.Length)
                {
                    return new ControlRun(_control, _defaultProperties);
                }

                return new TextCharacters(_text.AsMemory(), _defaultProperties);
            }
        }

        private class ControlRun : DrawableTextRun
        {
            private readonly Control _control;

            public ControlRun(Control control, TextRunProperties properties)
            {
                _control = control;
                Properties = properties;
            }

            public Control Control => _control;
            public override Size Size => _control.DesiredSize;
            public override double Baseline => 0;
            public override TextRunProperties? Properties { get; }

            public override void Draw(DrawingContext drawingContext, Point origin)
            {
                // noop
            }
        }
    }
}
