@namespace Lumeo
@implements IAsyncDisposable
@inject Lumeo.Services.IComponentInteropService Interop

<button @ref="_el"
        class="@CssClass"
        style="@StyleString"
        disabled="@Disabled"
        @attributes="AdditionalAttributes"
        @onclick="OnClick">
    <span class="relative z-10 inline-flex items-center justify-center gap-2">
        @ChildContent
    </span>
</button>

@code {
    [Parameter] public RenderFragment? ChildContent { get; set; }
    [Parameter] public EventCallback<Microsoft.AspNetCore.Components.Web.MouseEventArgs> OnClick { get; set; }
    [Parameter] public bool Shimmer { get; set; } = true;

    /// <summary>CSS color used for the shimmer sweep — defaults to a translucent foreground.</summary>
    [Parameter] public string? ShimmerColor { get; set; }

    [Parameter] public Button.ButtonVariant Variant { get; set; } = Button.ButtonVariant.Default;
    [Parameter] public Button.ButtonSize Size { get; set; } = Button.ButtonSize.Default;
    [Parameter] public bool Disabled { get; set; }

    /// <summary>
    /// Visual feedback when the button is pressed down. Default is <see cref="Button.ButtonPressEffect.None"/>
    /// (no press animation — original behaviour).
    /// </summary>
    [Parameter] public Button.ButtonPressEffect PressEffect { get; set; } = Button.ButtonPressEffect.None;

    [Parameter] public string? Class { get; set; }
    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }

    private Microsoft.AspNetCore.Components.ElementReference _el;
    private bool _rippleAttached;

    private const string BaseClasses = "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50";

    private string VariantClasses => Variant switch
    {
        Button.ButtonVariant.Default => "bg-primary text-primary-foreground shadow hover:bg-primary/90",
        Button.ButtonVariant.Destructive => "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
        Button.ButtonVariant.Outline => "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
        Button.ButtonVariant.Secondary => "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
        Button.ButtonVariant.Ghost => "hover:bg-accent hover:text-accent-foreground",
        Button.ButtonVariant.Link => "text-primary underline-offset-4 hover:underline",
        _ => ""
    };

    private string SizeClasses => Size switch
    {
        Button.ButtonSize.Default => "h-9 px-4 py-2",
        Button.ButtonSize.Sm => "h-8 rounded-md px-3 text-xs",
        Button.ButtonSize.Lg => "h-10 rounded-md px-8",
        Button.ButtonSize.Icon => "h-9 w-9",
        _ => ""
    };

    private string? PressEffectClass => PressEffect switch
    {
        Button.ButtonPressEffect.Scale => "lumeo-press-scale",
        Button.ButtonPressEffect.Brightness => "lumeo-press-brightness",
        Button.ButtonPressEffect.Ripple => "lumeo-press-ripple",
        _ => null
    };

    private string CssClass => string.Join(" ",
        new[] { BaseClasses, VariantClasses, SizeClasses, "cursor-pointer disabled:cursor-not-allowed", Shimmer ? "lumeo-shimmer" : null, PressEffectClass, Class }
            .Where(s => !string.IsNullOrWhiteSpace(s)));

    private string StyleString =>
        !string.IsNullOrWhiteSpace(ShimmerColor)
            ? $"--lumeo-shimmer-color: {ShimmerColor};"
            : string.Empty;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && PressEffect == Button.ButtonPressEffect.Ripple)
        {
            try
            {
                await Interop.RippleAttachAsync(_el);
                _rippleAttached = true;
            }
            catch (Microsoft.JSInterop.JSDisconnectedException) { }
        }
    }

    public async ValueTask DisposeAsync()
    {
        if (_rippleAttached)
        {
            try
            {
                await Interop.RippleDetachAsync(_el);
            }
            catch (Microsoft.JSInterop.JSDisconnectedException) { }
        }
    }
}
