@page "/tracks"
@page "/tracks/albums"
@page "/tracks/genres"
@page "/tracks/archive"
@using DeepDrftManager.Services
@inject CmsTrackBrowserViewModel VM
@inject ICmsTrackService CmsTrackService
@inject ISnackbar Snackbar
@inject ILogger<TrackList> Logger
@inject NavigationManager NavigationManager
@attribute [Authorize]

<PageTitle>Tracks — DeepDrft CMS</PageTitle>

<MudContainer MaxWidth="MaxWidth.Large" Class="mt-8">
    <MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="mb-4">
        <MudText Typo="Typo.h3">Tracks</MudText>

        @if (VM.Mode == BrowseMode.Tracks)
        {
            <MudButton Variant="Variant.Outlined"
                       Color="Color.Primary"
                       StartIcon="@Icons.Material.Filled.AutoFixHigh"
                       Disabled="@(_bulkRunning || (_grid?.GetMissingCount() ?? 0) == 0)"
                       OnClick="GenerateAllMissingAsync">
                @if (_bulkRunning)
                {
                    <MudProgressCircular Class="mr-2" Size="Size.Small" Indeterminate="true" />
                    <span>Generating @_bulkDone / @_bulkTotal…</span>
                }
                else
                {
                    <span>Generate All Missing (@(_grid?.GetMissingCount() ?? 0))</span>
                }
            </MudButton>
        }
    </MudStack>

    <MudToggleGroup T="BrowseMode"
                    Value="VM.Mode"
                    ValueChanged="OnModeChanged"
                    SelectionMode="SelectionMode.SingleSelection"
                    Color="Color.Primary"
                    Size="Size.Small"
                    Class="mb-4">
        <MudToggleItem Value="BrowseMode.Tracks">Tracks</MudToggleItem>
        <MudToggleItem Value="BrowseMode.Albums">Releases</MudToggleItem>
        <MudToggleItem Value="BrowseMode.Archive">Release Archive</MudToggleItem>
    </MudToggleGroup>

    @if (VM.Mode == BrowseMode.Tracks)
    {
        <CmsTrackGrid @ref="_grid" ShowAddButton="true" PageSize="20" OnStatusLoaded="StateHasChanged" />
    }
    else if (VM.Mode == BrowseMode.Albums)
    {
        <CmsAlbumBrowser Releases="VM.Albums"
                         IsLoading="VM.AlbumsLoading"
                         OnReleasesChanged="OnAlbumsChanged" />
    }
    else if (VM.Mode == BrowseMode.Archive)
    {
        <ReleaseArchiveBrowser />
    }
    else
    {
        @* Genre browse keeps its route (/tracks/genres) but lost its tab to Release Archive (§3.1).
           Reachable by direct URL; no longer in the toggle group. *@
        <CmsGenreBrowser Genres="VM.Genres"
                         IsLoading="VM.GenresLoading"
                         ExpandedGenre="@VM.ExpandedGenre"
                         OnExpandedGenreChanged="OnExpandedGenreChanged" />
    }
</MudContainer>

@code {
    private CmsTrackGrid? _grid;

    // The album browser owns its own row state and removes a deleted release locally. Invalidate the
    // VM cache so genres and album counts reflect the deletion on next mode switch.
    private void OnAlbumsChanged()
    {
        VM.Invalidate();
        StateHasChanged();
    }

    // Local state for the parent-owned "Generate All Missing" bulk run.
    private bool _bulkRunning;
    private int _bulkTotal;
    private int _bulkDone;

    protected override async Task OnInitializedAsync()
    {
        var uri = NavigationManager.Uri;
        var initial =
            uri.Contains("/tracks/albums", StringComparison.OrdinalIgnoreCase) ? BrowseMode.Albums
            : uri.Contains("/tracks/archive", StringComparison.OrdinalIgnoreCase) ? BrowseMode.Archive
            : uri.Contains("/tracks/genres", StringComparison.OrdinalIgnoreCase) ? BrowseMode.Genres
            : BrowseMode.Tracks;
        await VM.SwitchModeAsync(initial);
    }

    private async Task OnModeChanged(BrowseMode mode)
    {
        await VM.SwitchModeAsync(mode);
        var path = mode switch
        {
            BrowseMode.Albums => "/tracks/albums",
            BrowseMode.Archive => "/tracks/archive",
            BrowseMode.Genres => "/tracks/genres",
            _ => "/tracks"
        };
        NavigationManager.NavigateTo(path, replace: true);
        StateHasChanged();
    }

    private void OnExpandedGenreChanged(string? genre)
    {
        VM.SetExpandedGenre(genre);
        StateHasChanged();
    }

    /// <summary>
    /// Backfill every track missing a waveform profile, one request at a time so a large backfill
    /// does not flood the API with concurrent WAV decodes. On completion, refreshes the grid's
    /// status map so the per-row icons reflect the new state.
    /// </summary>
    private async Task GenerateAllMissingAsync()
    {
        var statusResult = await CmsTrackService.GetWaveformStatusAsync();
        if (!statusResult.Success || statusResult.Value is null)
        {
            var error = statusResult.Messages.FirstOrDefault()?.Message ?? "Unknown error";
            Snackbar.Add($"Failed to load waveform status: {error}", Severity.Error);
            return;
        }

        var missing = statusResult.Value.Where(s => !s.HasProfile).ToList();
        if (missing.Count == 0)
        {
            return;
        }

        _bulkRunning = true;
        _bulkTotal = missing.Count;
        _bulkDone = 0;
        _grid?.SetBulkRunning(true);
        var failures = 0;

        foreach (var status in missing)
        {
            try
            {
                var result = await CmsTrackService.GenerateWaveformProfileAsync(status.EntryKey);
                if (!result.Success)
                {
                    failures++;
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "Waveform generation failed for {EntryKey}", status.EntryKey);
                failures++;
            }
            _bulkDone++;
            StateHasChanged();
        }

        _bulkRunning = false;
        _grid?.SetBulkRunning(false);

        if (_grid is not null)
        {
            await _grid.RefreshWaveformStatusAsync();
        }

        var succeeded = missing.Count - failures;
        if (failures == 0)
        {
            Snackbar.Add($"Generated {succeeded} profile(s).", Severity.Success);
        }
        else
        {
            Snackbar.Add($"Generated {succeeded} profile(s); {failures} failed.", Severity.Warning);
        }
    }
}
