@using Microsoft.AspNetCore.Components.Forms

<MudPaper Class="pa-4" Elevation="2">
    <MudText Typo="Typo.h6" GutterBottom="true">Tracks</MudText>

    @if (AllowNewTracks)
    {
        <InputFile OnChange="HandleWavFilesSelected" accept=".wav,audio/wav,audio/x-wav" multiple disabled="@Disabled" />
    }

    @if (Tracks.Count == 0)
    {
        <MudText Typo="Typo.body2" Color="Color.Default" Class="mt-3">No tracks added yet.</MudText>
    }
    else
    {
        <MudList T="BatchRowModel" Class="mt-3">
            @for (var i = 0; i < Tracks.Count; i++)
            {
                var index = i;
                var row = Tracks[index];
                <div style="@RowStyle(index)" @onclick="() => SelectRow(index)">
                    <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Class="pa-2">
                        <MudText Typo="Typo.body2" Style="min-width: 1.5rem;">@(index + 1).</MudText>
                        <MudText Typo="Typo.body2" Style="flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">@row.TrackName</MudText>
                        @StatusChip(row)
                        <MudIconButton Icon="@Icons.Material.Filled.ArrowUpward"
                                       Size="Size.Small"
                                       Disabled="@(index == 0 || Disabled)"
                                       OnClick="@(() => OnMoveUp.InvokeAsync(index))"
                                       aria-label="Move track up" />
                        <MudIconButton Icon="@Icons.Material.Filled.ArrowDownward"
                                       Size="Size.Small"
                                       Disabled="@(index == Tracks.Count - 1 || Disabled)"
                                       OnClick="@(() => OnMoveDown.InvokeAsync(index))"
                                       aria-label="Move track down" />
                        @* Replace audio: existing (persisted) rows only. New rows still pick their WAV
                           via the file input above, so a replace control there would be redundant. A
                           native <label for> drives a per-row hidden InputFile — clicking the icon
                           opens that row's picker with zero JS (no eval, no programmatic .click()). *@
                        @if (row.Id.HasValue)
                        {
                            <label for="@ReplaceInputId(index)" @onclick:stopPropagation="true"
                                   style="display: inline-flex; @(Disabled ? "pointer-events: none; opacity: 0.5;" : "cursor: pointer;")">
                                <MudIcon Icon="@Icons.Material.Filled.SwapHoriz"
                                         Color="Color.Primary"
                                         Size="Size.Small"
                                         aria-label="Replace audio" />
                            </label>
                            <InputFile id="@ReplaceInputId(index)"
                                       OnChange="@(e => OnReplaceFileSelected.InvokeAsync((index, e.File)))"
                                       accept=".wav,audio/wav,audio/x-wav"
                                       disabled="@Disabled"
                                       style="display: none;" />
                        }
                        @* Remove: hidden for the sole remaining persisted track so a release can never
                           be track-deleted down to zero (that path soft-deletes the whole release). New
                           rows are always removable — dropping one only discards a pending upload. *@
                        @if (!(row.Id.HasValue && ExistingTrackCount <= 1))
                        {
                            <MudIconButton Icon="@Icons.Material.Filled.Delete"
                                           Color="Color.Error"
                                           Size="Size.Small"
                                           Disabled="@Disabled"
                                           OnClick="@(() => OnRemove.InvokeAsync(index))"
                                           aria-label="Remove track" />
                        }
                    </MudStack>
                    @if (row.Status == BatchRowStatus.Uploading)
                    {
                        <MudProgressLinear Color="Color.Info"
                                           Value="@row.UploadPercent"
                                           Class="mx-2 mb-2"
                                           aria-label="@($"Uploading {row.TrackName}")" />
                    }
                </div>
            }
        </MudList>
    }
</MudPaper>

@code {
    [Parameter] public List<BatchRowModel> Tracks { get; set; } = new();
    [Parameter] public int SelectedIndex { get; set; }
    [Parameter] public EventCallback<int> SelectedIndexChanged { get; set; }
    [Parameter] public bool Disabled { get; set; }
    [Parameter] public bool AllowNewTracks { get; set; } = true;

    /// <summary>
    /// Count of existing (persisted, Id-bearing) tracks in the list. When this is 1, the remove
    /// control on the sole persisted row is suppressed so a release cannot be track-deleted to zero
    /// (replace + release-level delete remain). New unsaved rows are excluded from this count.
    /// </summary>
    [Parameter] public int ExistingTrackCount { get; set; }

    [Parameter] public EventCallback<IReadOnlyList<IBrowserFile>> OnWavFilesSelected { get; set; }
    [Parameter] public EventCallback<int> OnMoveUp { get; set; }
    [Parameter] public EventCallback<int> OnMoveDown { get; set; }
    [Parameter] public EventCallback<int> OnRemove { get; set; }

    /// <summary>
    /// Raised when the admin picks a replacement WAV for an existing row, carrying the list index and
    /// the chosen file. Only fired for persisted (Id-bearing) rows.
    /// </summary>
    [Parameter] public EventCallback<(int Index, IBrowserFile File)> OnReplaceFileSelected { get; set; }

    // Stable per-row DOM id linking the swap-icon <label> to its hidden InputFile.
    private static string ReplaceInputId(int index) => $"replace-audio-input-{index}";

    private const int MaxFilesPerPick = 50;

    private Task SelectRow(int index) => SelectedIndexChanged.InvokeAsync(index);

    private Task HandleWavFilesSelected(InputFileChangeEventArgs e) =>
        OnWavFilesSelected.InvokeAsync(e.GetMultipleFiles(MaxFilesPerPick));

    private string RowStyle(int index)
    {
        const string baseStyle = "cursor: pointer; border-radius: 4px;";
        return index == SelectedIndex
            ? $"{baseStyle} background-color: var(--mud-palette-action-default-hover);"
            : baseStyle;
    }

    private RenderFragment StatusChip(BatchRowModel row) => row.Status switch
    {
        BatchRowStatus.Uploading => @<MudChip T="string" Size="Size.Small" Color="Color.Info" Variant="Variant.Text">
            <MudProgressCircular Indeterminate="true" Size="Size.Small" Class="mr-1" />Uploading</MudChip>,
        BatchRowStatus.Done => @<MudChip T="string" Size="Size.Small" Color="Color.Success" Variant="Variant.Text" Icon="@Icons.Material.Filled.CheckCircle">Done</MudChip>,
        BatchRowStatus.Failed => @<MudChip T="string" Size="Size.Small" Color="Color.Error" Variant="Variant.Text" Icon="@Icons.Material.Filled.Error">Failed</MudChip>,
        _ => @<MudChip T="string" Size="Size.Small" Color="Color.Default" Variant="Variant.Text">Queued</MudChip>
    };
}
