using System;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.JSInterop;
using Radzen.Blazor.Rendering;

namespace Radzen.Blazor
{
    /// <summary>
    /// The display style of the text. It overrides the tag name and provides predefined styling.
    /// </summary>
    public enum TextStyle
    {
        /// <summary>Display as largest header.</summary>
        DisplayH1,
        /// <summary>Display as second largest header.</summary>
        DisplayH2,
        /// <summary>Display as third largest header.</summary>
        DisplayH3,
        /// <summary>Display as fourth largest header.</summary>
        DisplayH4,
        /// <summary>Display as fifth largest header.</summary>
        DisplayH5,
        /// <summary>Display as sixth largest header.</summary>
        DisplayH6,
        /// <summary>Display as H1 element.</summary>
        H1,
        /// <summary>Display as H2 element.</summary>
        H2,
        /// <summary>Display as H3 element.</summary>
        H3,
        /// <summary>Display as H4 element.</summary>
        H4,
        /// <summary>Display as H5 element.</summary>
        H5,
        /// <summary>Display as H6 element.</summary>
        H6,
        /// <summary>Display as subtitle.</summary>
        Subtitle1,
        /// <summary>Display as a smaller subtitle.</summary>
        Subtitle2,
        /// <summary>Display as a paragraph.</summary>
        Body1,
        /// <summary>Display as a smaller paragraph.</summary>
        Body2,
        /// <summary>Display as button text.</summary>
        Button,
        /// <summary>Display as a caption.</summary>
        Caption,
        /// <summary>Display as overline.</summary>
        Overline
    }

    /// <summary>
    /// The tag name of the element that will be rendered.
    /// </summary>

    public enum TagName
    {
        /// <summary>Use &lt;div&gt; to render the text.</summary>
        Div,
        /// <summary>Use &lt;span&gt; to render the text.</summary>
        Span,
        /// <summary>Use &lt;p&gt; to render the text.</summary>
        P,
        /// <summary>Use &lt;h1&gt; to render the text.</summary>
        H1,
        /// <summary>Use &lt;h2&gt; to render the text.</summary>
        H2,
        /// <summary>Use &lt;h3&gt; to render the text.</summary>
        H3,
        /// <summary>Use &lt;h4&gt; to render the text.</summary>
        H4,
        /// <summary>Use &lt;h5&gt; to render the text.</summary>
        H5,
        /// <summary>Use &lt;h6&gt; to render the text.</summary>
        H6,
        /// <summary>Use &lt;a&gt; to render the text.</summary>
        A,
        /// <summary>Use &lt;button&gt; to render the text.</summary>
        Button,
        /// <summary>Use &lt;pre&gt; to render the text.</summary>
        Pre,
        /// <summary>The tag name will be determined depending on the TextStyle.</summary>
        Auto
    }
    /// <summary>
    /// A text display component with predefined typography styles matching Material Design text hierarchy.
    /// RadzenText provides consistent text formatting for headings, subtitles, body text, captions, and more with semantic HTML tags.
    /// Simplifies typography by providing preset styles that match your theme's design system, allowing consistent, professionally designed text formatting without managing CSS classes manually.
    /// Supports text styles (Display headings H1-H6, subtitles, body text, captions, button text, overlines), automatically uses appropriate HTML tags (h1-h6, p, span) based on style,
    /// manual HTML tag specification via TagName property, built-in text alignment (left, right, center, justify), and optional anchor links for heading navigation.
    /// TextStyle.DisplayH1-H6 provide large display headings, TextStyle.H1-H6 provide standard headings, Subtitle1/2 for subtitles, Body1/2 for paragraphs, Caption for small text, and Overline for labels.
    /// </summary>
    /// <example>
    /// Heading text:
    /// <code>
    /// &lt;RadzenText TextStyle="TextStyle.H3"&gt;Welcome to Our Application&lt;/RadzenText&gt;
    /// </code>
    /// Subtitle with alignment:
    /// <code>
    /// &lt;RadzenText TextStyle="TextStyle.Subtitle1" TextAlign="TextAlign.Center"&gt;
    ///     This is a centered subtitle
    /// &lt;/RadzenText&gt;
    /// </code>
    /// Body text with custom tag:
    /// <code>
    /// &lt;RadzenText TextStyle="TextStyle.Body1" TagName="TagName.Div"&gt;
    ///     This is body text rendered as a div element.
    /// &lt;/RadzenText&gt;
    /// </code>
    /// </example>
    public class RadzenText : RadzenComponent
    {
        class RadzenTextAnchor : ComponentBase, IDisposable
        {
            [Inject]
            NavigationManager? NavigationManager { get; set; }

            [Inject]
            IJSRuntime? JSRuntime { get; set; }

            [Parameter]
            public string? Path { get; set; }

            private string GetAnchor()
            {
                if (string.IsNullOrEmpty(Path))
                {
                    return "";
                }

                var fragments = Path.Split('#');

                return fragments.Length > 1 ? fragments[1] : fragments[0];
            }

            private ElementReference element;

            protected override void OnInitialized()
            {
                if (NavigationManager != null)
                {
                    NavigationManager.LocationChanged += OnLocationChanged;
                }
            }

            void OnLocationChanged(object? sender, LocationChangedEventArgs e)
            {
                if (e != null && e.Location.EndsWith(GetAnchor(), StringComparison.InvariantCultureIgnoreCase) && JSRuntime != null)
                {
                    JSRuntime.InvokeVoidAsync("Element.prototype.scrollIntoView.call", element);
                }
            }

            private string GetPath()
            {
                if (NavigationManager == null)
                {
                    return "";
                }

                var uri = new Uri(NavigationManager.Uri);

                var anchor = GetAnchor();

                return $"{uri.PathAndQuery}#{anchor}";
            }

            protected override void BuildRenderTree(RenderTreeBuilder builder)
            {
                ArgumentNullException.ThrowIfNull(builder);
                builder.OpenElement(1, "a");
                builder.AddAttribute(2, "id", GetAnchor());
                builder.AddAttribute(3, "href", GetPath());
                builder.AddAttribute(4, "class", "rz-link");
                builder.AddElementReferenceCapture(6, capture => element = capture);
                builder.OpenComponent<RadzenIcon>(7);
                builder.AddAttribute(8, "Icon", "link");
                builder.CloseComponent();

                builder.CloseElement();
            }

            void IDisposable.Dispose()
            {
                if (NavigationManager != null)
                {
                    NavigationManager.LocationChanged -= OnLocationChanged;
                }
            }
        }

        /// <summary>
        /// Gets or sets the plain text content to display.
        /// For simple text display, use this property. For rich content with markup, use <see cref="ChildContent"/> instead.
        /// When set, takes precedence over ChildContent.
        /// </summary>
        /// <value>The text content to display.</value>
        [Parameter]
        public string? Text { get; set; }

        /// <summary>
        /// Gets or sets the child content (markup) to display.
        /// Use this for rich content with HTML or other Blazor components. Overridden by <see cref="Text"/> if both are set.
        /// </summary>
        /// <value>The child content render fragment.</value>
        [Parameter]
        public RenderFragment? ChildContent { get; set; }

        /// <summary>
        /// Gets or sets the typography style that determines the text size, weight, and appearance.
        /// Options include display headings (DisplayH1-H6), standard headings (H1-H6), subtitles, body text, captions, and more.
        /// Each style provides consistent formatting matching the theme's design system.
        /// </summary>
        /// <value>The text style. Default is <see cref="TextStyle.Body1"/>.</value>
        [Parameter]
        public TextStyle TextStyle { get; set; } = TextStyle.Body1;

        /// <summary>
        /// Gets or sets the horizontal text alignment within the container.
        /// Options include Left, Right, Center, Justify, Start, End, and JustifyAll.
        /// </summary>
        /// <value>The text alignment. Default is <see cref="TextAlign.Left"/>.</value>
        [Parameter]
        public TextAlign TextAlign { get; set;} = TextAlign.Left;

        /// <summary>
        /// Gets or sets the HTML element tag to render.
        /// When set to Auto (default), the tag is chosen automatically based on <see cref="TextStyle"/>
        /// (e.g., H1 style uses &lt;h1&gt; tag). Override to use a specific tag regardless of style.
        /// </summary>
        /// <value>The HTML tag name. Default is <see cref="TagName.Auto"/>.</value>
        [Parameter]
        public TagName TagName { get; set; } = TagName.Auto;

        /// <summary>
        /// Gets or sets an anchor identifier for creating linkable headings.
        /// When set, adds a clickable link icon next to the text that scrolls to this element when clicked.
        /// The anchor href will be the current page URL with #anchorname appended.
        /// </summary>
        /// <value>The anchor identifier for heading links.</value>
        [Parameter]
        public string? Anchor { get; set; }

        /// <inheritdoc />
        protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            ArgumentNullException.ThrowIfNull(builder);
            var tagName = "span";
            var className = "";
            var alignClassName = "";

            switch (TextStyle)
            {
                case TextStyle.DisplayH1:
                    tagName = "h1";
                    className = "rz-text-display-h1";
                    break;
                case TextStyle.DisplayH2:
                    tagName = "h2";
                    className = "rz-text-display-h2";
                    break;
                case TextStyle.DisplayH3:
                    tagName = "h3";
                    className = "rz-text-display-h3";
                    break;
                case TextStyle.DisplayH4:
                    tagName = "h4";
                    className = "rz-text-display-h4";
                    break;
                case TextStyle.DisplayH5:
                    tagName = "h5";
                    className = "rz-text-display-h5";
                    break;
                case TextStyle.DisplayH6:
                    tagName = "h6";
                    className = "rz-text-display-h6";
                    break;
                case TextStyle.H1:
                    tagName = "h1";
                    className = "rz-text-h1";
                    break;
                case TextStyle.H2:
                    tagName = "h2";
                    className = "rz-text-h2";
                    break;
                case TextStyle.H3:
                    tagName = "h3";
                    className = "rz-text-h3";
                    break;
                case TextStyle.H4:
                    tagName = "h4";
                    className = "rz-text-h4";
                    break;
                case TextStyle.H5:
                    tagName = "h5";
                    className = "rz-text-h5";
                    break;
                case TextStyle.H6:
                    tagName = "h6";
                    className = "rz-text-h6";
                    break;
                case TextStyle.Subtitle1:
                    tagName = "h6";
                    className = "rz-text-subtitle1";
                    break;
                case TextStyle.Subtitle2:
                    tagName = "h6";
                    className = "rz-text-subtitle2";
                    break;
                case TextStyle.Body1:
                    tagName = "p";
                    className = "rz-text-body1";
                    break;
                case TextStyle.Body2:
                    tagName = "p";
                    className = "rz-text-body2";
                    break;
                case TextStyle.Button:
                    tagName = "span";
                    className = "rz-text-button";
                    break;
                case TextStyle.Caption:
                    tagName = "span";
                    className = "rz-text-caption";
                    break;
                case TextStyle.Overline:
                    tagName = "span";
                    className = "rz-text-overline";
                    break;
            }

            switch (TextAlign)
            {
                case TextAlign.Center:
                    alignClassName = "rz-text-align-center";
                    break;
                case TextAlign.End:
                    alignClassName = "rz-text-align-end";
                    break;
                case TextAlign.Justify:
                    alignClassName = "rz-text-align-justify";
                    break;
                case TextAlign.Start:
                    alignClassName = "rz-text-align-start";
                    break;
                case TextAlign.Left:
                    alignClassName = "rz-text-align-left";
                    break;
                case TextAlign.Right:
                    alignClassName = "rz-text-align-right";
                    break;
                case TextAlign.JustifyAll:
                    alignClassName = "rz-text-align-justify-all";
                    break;
            }

            switch (TagName)
            {
                case TagName.Div:
                    tagName = "div";
                    break;
                case TagName.Span:
                    tagName = "span";
                    break;
                case TagName.P:
                    tagName = "p";
                    break;
                case TagName.H1:
                    tagName = "h1";
                    break;
                case TagName.H2:
                    tagName = "h2";
                    break;
                case TagName.H3:
                    tagName = "h3";
                    break;
                case TagName.H4:
                    tagName = "h4";
                    break;
                case TagName.H5:
                    tagName = "h5";
                    break;
                case TagName.H6:
                    tagName = "h6";
                    break;
                case TagName.A:
                    tagName = "a";
                    break;
                case TagName.Button:
                    tagName = "button";
                    break;
                case TagName.Pre:
                    tagName = "pre";
                    break;
            }

            var @class = ClassList.Create(className)
                                  .Add(Attributes)
                                  .Add(alignClassName, TextAlign != TextAlign.Left)
                                  .ToString();

            if (Visible)
            {
                builder.OpenElement(0, tagName);
                builder.AddAttribute(1, "style", Style);
                builder.AddMultipleAttributes(2, Attributes);
                builder.AddAttribute(3, "class", @class);
                builder.AddAttribute(4, "id", GetId());

                if (!string.IsNullOrEmpty(Text))
                {
                    builder.AddContent(5, Text);
                }
                else
                {
                    builder.AddContent(5, ChildContent);
                }

                if (!string.IsNullOrEmpty(Anchor))
                {
                    builder.OpenComponent<RadzenTextAnchor>(6);
                    builder.AddAttribute(7, nameof(RadzenTextAnchor.Path), Anchor);
                    builder.CloseComponent();
                }
                builder.AddElementReferenceCapture(8, capture => Element = capture);
                builder.CloseElement();
            }
        }
    }
}