@namespace Lumeo
@using Lumeo.Services
@implements IAsyncDisposable

@if (Shell is not null)
{
    @* See OverlayShellMarker — host DialogContent already painted the shell.
       Pass children through to avoid a second backdrop + panel. *@
    @ChildContent
}
else if (Context.IsOpen)
{
    <div class="fixed inset-0 z-50 flex items-center justify-center">
        <!-- Backdrop -->
        <div class="fixed inset-0 bg-black/80 animate-fade-in" @onclick="HandleBackdropClick"></div>
        <!-- Content -->
        <div id="@_contentId" class="@CssClass" role="dialog" aria-modal="true" aria-labelledby="@Context.TitleId" aria-describedby="@Context.DescriptionId" @onkeydown="HandleKeyDown" tabindex="-1" @attributes="AdditionalAttributes">
            @if (Scrollable)
            {
                <div class="max-h-[85vh] overflow-y-auto">
                    @ChildContent
                </div>
            }
            else
            {
                @ChildContent
            }
            @if (!PreventClose)
            {
                <button class="absolute right-2 top-2 sm:right-4 sm:top-4 inline-flex items-center justify-center rounded-sm h-11 w-11 sm:h-6 sm:w-6 opacity-70 transition-opacity hover:opacity-100 focus:outline-none" @onclick="Close">
                    <Blazicon Svg="Lucide.X" class="h-4 w-4" />
                    <span class="sr-only">@L["Dialog.Close"]</span>
                </button>
            }
        </div>
    </div>
}

@inject ComponentInteropService Interop
@inject Lumeo.Services.Localization.ILumeoLocalizer L

@code {
    [CascadingParameter] public Dialog.DialogContext Context { get; set; } = default!;
    [CascadingParameter] public OverlayShellMarker? Shell { get; set; }
    [Parameter] public RenderFragment? ChildContent { get; set; }
    [Parameter] public bool PreventClose { get; set; }
    [Parameter] public DialogSize Size { get; set; } = DialogSize.Default;
    [Parameter] public bool Scrollable { get; set; }
    [Parameter] public string? Class { get; set; }
    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }

    private readonly string _contentId = $"dialog-{Guid.NewGuid():N}";
    private bool _wasOpen;

    private string SizeClass => Size switch
    {
        DialogSize.Sm => "max-w-sm",
        DialogSize.Default => "max-w-lg",
        DialogSize.Lg => "max-w-2xl",
        DialogSize.Xl => "max-w-4xl",
        DialogSize.Full => "max-w-[calc(100vw-2rem)] max-h-[calc(100vh-2rem)]",
        _ => "max-w-lg"
    };

    private string CssClass => $"relative z-50 grid w-full {SizeClass} gap-4 bg-background p-6 shadow-lg animate-zoom-in sm:rounded-lg {Class}".Trim();

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // Passthrough mode — host DialogContent owns lifecycle effects.
        if (Shell is not null) return;

        if (Context.IsOpen && !_wasOpen)
        {
            await Interop.LockScroll();
            await Interop.SetupFocusTrap(_contentId);
            _wasOpen = true;
        }
        else if (!Context.IsOpen && _wasOpen)
        {
            await Cleanup();
            _wasOpen = false;
        }
    }

    private async Task Close() => await Context.SetOpen.InvokeAsync(false);

    private async Task HandleBackdropClick()
    {
        if (!PreventClose) await Close();
    }

    private async Task HandleKeyDown(KeyboardEventArgs e)
    {
        if (e.Key == "Escape" && !PreventClose)
        {
            await Close();
        }
    }

    private async Task Cleanup()
    {
        try
        {
            await Interop.RemoveFocusTrap(_contentId);
            await Interop.UnlockScroll();
        }
        catch (JSDisconnectedException) { }
    }

    public async ValueTask DisposeAsync()
    {
        if (_wasOpen)
        {
            await Cleanup();
        }
    }

    public enum DialogSize { Sm, Default, Lg, Xl, Full }
}
