using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Media;
using Markdig;
using MarkdownEditor.Views.Renderers;

namespace MarkdownEditor.Views;

/// <summary>
/// A control that renders markdown text into formatted Avalonia UI elements.
/// Uses a modular renderer system for extensibility and maintainability.
/// </summary>
public class MarkdownViewer : UserControl
{
    /// <summary>
    /// Defines the Markdown property for binding.
    /// </summary>
    public static readonly StyledProperty<string?> MarkdownProperty =
        AvaloniaProperty.Register<MarkdownViewer, string?>(nameof(Markdown));

    /// <summary>
    /// Gets or sets the markdown content to render.
    /// </summary>
    public string? Markdown
    {
        get => GetValue(MarkdownProperty);
        set => SetValue(MarkdownProperty, value);
    }

    private readonly SelectableTextBlock _textBlock;
    private readonly ScrollViewer _scrollViewer;
    private readonly MarkdownPipeline _pipeline;
    private MarkdownRendererCoordinator? _rendererCoordinator;

    /// <summary>
    /// Initializes a new instance of the <see cref="MarkdownViewer"/> class.
    /// </summary>
    public MarkdownViewer()
    {
        _textBlock = new SelectableTextBlock
        {
            Margin = new Thickness(10),
            TextWrapping = TextWrapping.Wrap
        };
        
        _scrollViewer = new ScrollViewer
        {
            Content = _textBlock,
            HorizontalScrollBarVisibility = Avalonia.Controls.Primitives.ScrollBarVisibility.Auto,
            VerticalScrollBarVisibility = Avalonia.Controls.Primitives.ScrollBarVisibility.Auto
        };
        Content = _scrollViewer;

        _pipeline = new MarkdownPipelineBuilder()
            .UseAdvancedExtensions()
            .Build();
    }

    /// <inheritdoc/>
    protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
    {
        base.OnPropertyChanged(change);

        if (change.Property == MarkdownProperty || 
            change.Property == ForegroundProperty ||
            change.Property == BackgroundProperty ||
            change.Property == FontSizeProperty)
        {
            RenderMarkdown();
        }
    }

    /// <summary>
    /// Renders the current markdown content into the view.
    /// </summary>
    private void RenderMarkdown()
    {
        // Clear existing inlines
        if (_textBlock.Inlines != null)
        {
            _textBlock.Inlines.Clear();
        }

        if (string.IsNullOrWhiteSpace(Markdown))
            return;

        try
        {
            // Determine if we're in dark mode based on background brightness
            bool isDarkMode = true;
            if (Background is SolidColorBrush bgBrush)
            {
                var color = bgBrush.Color;
                var brightness = (color.R * 299 + color.G * 587 + color.B * 114) / 1000;
                isDarkMode = brightness < 128;
            }

            // Calculate font scale factor (base size is 14)
            double fontScale = FontSize / 14.0;

            // Set base font size and colors
            _textBlock.FontSize = FontSize;
            _textBlock.Foreground = Foreground;

            // Create coordinator with theme-aware colors and font scale
            _rendererCoordinator = new MarkdownRendererCoordinator(isDarkMode, fontScale);
            
            var document = Markdig.Markdown.Parse(Markdown, _pipeline);
            
            // Render all blocks into a single SelectableTextBlock's Inlines collection
            // This enables text selection across multiple blocks
            if (_textBlock.Inlines != null)
            {
                _rendererCoordinator.RenderBlocksToInlines(document, _textBlock.Inlines);
            }
        }
        catch (Exception ex)
        {
            if (_textBlock.Inlines != null)
            {
                _textBlock.Inlines.Clear();
                _textBlock.Inlines.Add(new Run($"Error rendering markdown: {ex.Message}")
                {
                    Foreground = Brushes.Red
                });
            }
        }
    }
}
