@page "/tracks/mixes"
@inherits CmsMediumBrowserBase<CmsMixBrowser.MixRow>
@using DeepDrftModels.DTOs
@using DeepDrftModels.Enums
@attribute [Authorize]
@inject ILogger<CmsMixBrowser> Logger

@* Embedded as the MIXES tab content of the Release Archive (Phase 9 §8.A), and still routable at
   /tracks/mixes for direct-URL access. The grid is the rich CmsAlbumBrowser filtered to Mixes (§8.C
   parity: expand-tracks, delete, Type chip, per-row edit), with the Mix waveform generate supplied as
   its medium-specific special-action column so that affordance survives the move off the thin table.
   When embedded, the page chrome (title, container, the now-meaningless "Back to Release Archive"
   button) is suppressed; the standalone route keeps it. The waveform affordance (9.5.E) is preserved
   in both. *@
@if (Embedded)
{
    @GridContent
}
else
{
    <PageTitle>Mixes — DeepDrft CMS</PageTitle>

    <MudContainer MaxWidth="MaxWidth.Large" Class="mt-8">
        <MudButton Variant="Variant.Text"
                   StartIcon="@Icons.Material.Filled.ArrowBack"
                   Href="/tracks/archive"
                   Class="mb-4">
            Back to Release Archive
        </MudButton>

        <MudText Typo="Typo.h4" GutterBottom="true">Mixes</MudText>

        @GridContent
    </MudContainer>
}

@code {
    /// <summary>
    /// True when rendered as tab content inside the Release Archive; suppresses the standalone page
    /// chrome (title, container, back button). False (default) renders the full routable page.
    /// </summary>
    [Parameter] public bool Embedded { get; set; }

    protected override ReleaseMedium Medium => ReleaseMedium.Mix;
    protected override string MediumNoun => "mixes";

    protected override MixRow ToRow(ReleaseDto release) => new()
    {
        Release = release,
        HasWaveform = !string.IsNullOrEmpty(release.MixMetadata?.WaveformEntryKey)
    };

    protected override ReleaseDto ReleaseOf(MixRow row) => row.Release;

    // The grid itself — identical in the embedded and standalone contexts. Defined once as a fragment so
    // both branches above render the same markup without duplication. The Mix declares one dedicated
    // "Waveform" special-action column; the grid renders it between Tracks and Actions, handing the cell
    // each release, and RowFor recovers the matching MixRow's generate state.
    private RenderFragment GridContent => @<CmsAlbumBrowser Releases="Releases"
                                                           IsLoading="Loading"
                                                           OnReleasesChanged="ReloadAsync"
                                                           SpecialColumns="_specialColumns" />;

    // Allocated once per component instance in OnInitialized (field initializers cannot reference
    // instance members, so initialization is deferred to the first lifecycle hook).
    private IReadOnlyList<SpecialActionColumn> _specialColumns = Array.Empty<SpecialActionColumn>();

    protected override void OnInitialized()
    {
        _specialColumns = new[] { new SpecialActionColumn("Waveform", WaveformCell) };
        base.OnInitialized();
    }

    // Per-row cell for the dedicated "Waveform" column: status icon plus generate/regenerate button with
    // progress. Recovers the typed MixRow via RowFor; skips rendering for a release not on the page.
    private RenderFragment<ReleaseDto> WaveformCell => release =>@<text>
        @{ var row = RowFor(release); }
        @if (row is not null)
        {
            @if (row.HasWaveform)
            {
                <MudTooltip Text="Waveform generated">
                    <MudIcon Icon="@Icons.Material.Filled.CheckCircle" Color="Color.Success" Size="Size.Small" />
                </MudTooltip>
            }
            else
            {
                <MudTooltip Text="No waveform — incomplete">
                    <MudIcon Icon="@Icons.Material.Filled.Cancel" Color="Color.Warning" Size="Size.Small" />
                </MudTooltip>
            }
            <MudButton Variant="Variant.Outlined"
                       Size="Size.Small"
                       StartIcon="@Icons.Material.Filled.GraphicEq"
                       Disabled="@row.IsGenerating"
                       OnClick="@(() => GenerateWaveformAsync(row))">
                @if (row.IsGenerating)
                {
                    <MudProgressCircular Class="mr-2" Size="Size.Small" Indeterminate="true" />
                    <span>Generating…</span>
                }
                else
                {
                    <span>@(row.HasWaveform ? "Regenerate" : "Generate")</span>
                }
            </MudButton>
        }
    </text>;

    private async Task GenerateWaveformAsync(MixRow row)
    {
        row.IsGenerating = true;
        StateHasChanged();
        try
        {
            var result = await CmsReleaseService.GenerateMixWaveformAsync(row.Release.Id);
            if (result.Success)
            {
                // Optimistic update: the trigger succeeded, so the waveform is stored. Unlike SessionBrowser's
                // re-fetch (which retrieves the server-generated HeroImageEntryKey), there is nothing to reflect
                // back here — HasWaveform is derived from WaveformEntryKey being non-null, which we know is now set.
                row.HasWaveform = true;
                Snackbar.Add($"Generated waveform for '{row.Release.Title}'.", Severity.Success);
            }
            else
            {
                var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error";
                Snackbar.Add($"Waveform generation failed for '{row.Release.Title}': {error}", Severity.Error);
            }
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Waveform generation failed for release {ReleaseId}", row.Release.Id);
            Snackbar.Add($"Waveform generation failed for '{row.Release.Title}' — please try again.", Severity.Error);
        }
        finally
        {
            row.IsGenerating = false;
            StateHasChanged();
        }
    }

    public sealed class MixRow
    {
        public required ReleaseDto Release { get; set; }
        public bool HasWaveform { get; set; }
        public bool IsGenerating { get; set; }
    }
}
