using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Radzen.Blazor.Rendering;
using System;
using System.Threading.Tasks;

namespace Radzen.Blazor
{
    /// <summary>
    /// A clickable button component that supports various visual styles, icons, images, and loading states.
    /// RadzenButton provides a consistent and accessible way to trigger actions in your Blazor application.
    /// Supports multiple visual variants (Filled, Flat, Outlined, Text), color styles (Primary, Secondary, Success, etc.), 
    /// and sizes (ExtraSmall, Small, Medium, Large). It can display text, icons, images, or a combination of these.
    /// When <see cref="IsBusy"/> is true, the button shows a loading indicator and becomes disabled.
    /// </summary>
    /// <example>
    /// Basic usage with text and click handler:
    /// <code>
    /// &lt;RadzenButton Click=@(args => Console.WriteLine("Button clicked")) Text="Click Me" /&gt;
    /// </code>
    /// Button with icon and custom style:
    /// <code>
    /// &lt;RadzenButton Icon="save" Text="Save" ButtonStyle="ButtonStyle.Success" Variant="Variant.Flat" Size="ButtonSize.Large" /&gt;
    /// </code>
    /// Button with busy state:
    /// <code>
    /// &lt;RadzenButton IsBusy=@isSaving BusyText="Saving..." Text="Save" Click=@SaveData /&gt;
    /// </code>
    /// </example>
    public partial class RadzenButton : RadzenComponent
    {
        /// <summary>
        /// Gets or sets the custom child content to be rendered inside the button.
        /// When set, this content will be displayed instead of the <see cref="Text"/>, <see cref="Icon"/>, or <see cref="Image"/>.
        /// </summary>
        /// <value>The child content.</value>
        [Parameter]
        public RenderFragment? ChildContent { get; set; }

        /// <summary>
        /// Gets or sets the tab index for keyboard navigation.
        /// Controls the order in which the button receives focus when the user presses the Tab key.
        /// </summary>
        /// <value>The tab index. Default value is 0.</value>
        [Parameter]
        public int TabIndex { get; set; } = 0;

        /// <summary>
        /// Gets or sets the text label displayed on the button.
        /// If both <see cref="Text"/> and <see cref="Icon"/> are set, both will be displayed.
        /// </summary>
        /// <value>The button text. Default is empty string.</value>
        [Parameter]
        public string Text { get; set; } = "";

        private string? imageAlternateText;

        /// <summary>
        /// Gets or sets the alternate text for the button's image.
        /// This is used as the alt attribute when an <see cref="Image"/> is specified, improving accessibility.
        /// </summary>
        /// <value>The image alternate text. Default is "button".</value>
        [Parameter]
        public string ImageAlternateText { get => imageAlternateText ?? Localize(nameof(RadzenStrings.Button_ImageAlternateText)); set => imageAlternateText = value; }

        /// <summary>
        /// Gets or sets the Material icon name to be displayed in the button.
        /// Use Material Symbols icon names (e.g., "save", "delete", "add"). The icon will be rendered using the rzi icon font.
        /// </summary>
        /// <value>The Material icon name.</value>
        [Parameter]
        public string? Icon { get; set; }

        /// <summary>
        /// Gets or sets a custom color for the icon.
        /// This overrides the default icon color determined by the button's <see cref="ButtonStyle"/> and <see cref="Variant"/>.
        /// Supports any valid CSS color value (e.g., "#FF0000", "rgb(255, 0, 0)", "var(--my-color)").
        /// </summary>
        /// <value>The icon color as a CSS color value.</value>
        [Parameter]
        public string? IconColor { get; set; }

        /// <summary>
        /// Gets or sets the URL of an image to be displayed in the button.
        /// The image will be rendered as an img element. For icon fonts, use the <see cref="Icon"/> property instead.
        /// </summary>
        /// <value>The image URL or path.</value>
        [Parameter]
        public string? Image { get; set; }

        /// <summary>
        /// Gets or sets the semantic color style of the button.
        /// Determines the button's color scheme based on its purpose (e.g., Primary for main actions, Danger for destructive actions).
        /// </summary>
        /// <value>The button style. Default is <see cref="ButtonStyle.Primary"/>.</value>
        [Parameter]
        public ButtonStyle ButtonStyle { get; set; } = ButtonStyle.Primary;

        /// <summary>
        /// Gets or sets the HTML button type attribute.
        /// Use <see cref="ButtonType.Submit"/> for form submissions or <see cref="ButtonType.Button"/> for regular clickable buttons.
        /// </summary>
        /// <value>The button type. Default is <see cref="ButtonType.Button"/>.</value>
        [Parameter]
        public ButtonType ButtonType { get; set; } = ButtonType.Button;

        /// <summary>
        /// Gets or sets the design variant that controls the button's visual appearance.
        /// Options include Filled (solid background), Flat (subtle background), Outlined (border only), and Text (minimal styling).
        /// </summary>
        /// <value>The button variant. Default is <see cref="Variant.Filled"/>.</value>
        [Parameter]
        public virtual Variant Variant { get; set; } = Variant.Filled;

        /// <summary>
        /// Gets or sets the color intensity shade for the button.
        /// Works in combination with <see cref="ButtonStyle"/> to adjust the color darkness/lightness.
        /// </summary>
        /// <value>The color shade. Default is <see cref="Shade.Default"/>.</value>
        [Parameter]
        public virtual Shade Shade { get; set; } = Shade.Default;

        /// <summary>
        /// Gets or sets the button size.
        /// Controls the padding, font size, and overall dimensions of the button.
        /// </summary>
        /// <value>The button size. Default is <see cref="ButtonSize.Medium"/>.</value>
        [Parameter]
        public virtual ButtonSize Size { get; set; } = ButtonSize.Medium;

        /// <summary>
        /// Gets or sets whether the button is disabled and cannot be clicked.
        /// When true, the button will have a disabled appearance and will not respond to user interactions.
        /// </summary>
        /// <value><c>true</c> if the button is disabled; otherwise, <c>false</c>. Default is <c>false</c>.</value>
        [Parameter]
        public bool Disabled { get; set; }

        /// <summary>
        /// Gets or sets the callback invoked when the button is clicked.
        /// This event will not fire if the button is <see cref="Disabled"/> or <see cref="IsBusy"/>.
        /// </summary>
        /// <value>The click event callback.</value>
        [Parameter]
        public EventCallback<MouseEventArgs> Click { get; set; }

        /// <summary>
        /// Gets or sets whether the button is in a busy/loading state.
        /// When true, the button displays a loading indicator, shows the <see cref="BusyText"/>, and becomes disabled.
        /// This is useful for indicating asynchronous operations are in progress.
        /// </summary>
        /// <value><c>true</c> if the button is busy; otherwise, <c>false</c>. Default is <c>false</c>.</value>
        [Parameter]
        public bool IsBusy { get; set; }

        /// <summary>
        /// Gets or sets the text displayed when the button is in a busy state (<see cref="IsBusy"/> is true).
        /// If not set, the button will show a loading indicator without text.
        /// </summary>
        /// <value>The busy state text. Default is empty string.</value>
        [Parameter]
        public string BusyText { get; set; } = "";

        /// <summary>
        /// Gets a value indicating whether this button is effectively disabled.
        /// The button is disabled if either <see cref="Disabled"/> is true or <see cref="IsBusy"/> is true.
        /// </summary>
        /// <value><c>true</c> if the button is disabled or busy; otherwise, <c>false</c>.</value>
        public bool IsDisabled { get => Disabled || IsBusy; }


        bool clicking;
        /// <summary>
        /// Handles the button click event. This method is called internally when the button is clicked.
        /// It prevents multiple simultaneous clicks and invokes the <see cref="Click"/> callback.
        /// </summary>
        /// <param name="args">The mouse event arguments containing click information.</param>
        /// <returns>A task representing the asynchronous operation.</returns>
        public virtual async Task OnClick(MouseEventArgs args)
        {
            if (clicking)
            {
                return;
            }

            try
            {
                clicking = true;

                await Click.InvokeAsync(args);
            }
            finally
            {
                clicking = false;
            }
        }

        /// <inheritdoc />
        protected override string GetComponentCssClass() => ClassList.Create("rz-button")
                                                                     .AddButtonSize(Size)
                                                                     .AddVariant(Variant)
                                                                     .AddButtonStyle(ButtonStyle)
                                                                     .AddDisabled(IsDisabled)
                                                                     .AddShade(Shade)
                                                                     .Add($"rz-button-icon-only", string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Icon))
                                                                     .ToString();
    }
}
