@using System.Net
@using DeepDrftManager.Services
@using DeepDrftModels.DTOs
@inject ICmsTrackService CmsTrackService
@inject IDialogService DialogService
@inject ISnackbar Snackbar
@inject ILogger<CmsTrackGrid> Logger
@inject NavigationManager NavigationManager

@if (ShowAddButton)
{
    <MudStack Row="true" Justify="Justify.FlexEnd" Class="mb-2">
        <MudButton Variant="Variant.Filled"
                   Color="Color.Primary"
                   StartIcon="@Icons.Material.Filled.Add"
                   Href="/tracks/upload">
            Add Track
        </MudButton>
    </MudStack>
}

<MudTable T="TrackDto"
          @ref="_table"
          ServerData="LoadServerData"
          Hover="true"
          Striped="true"
          Dense="true"
          Bordered="false"
          FixedHeader="true"
          RowsPerPage="@PageSize"
          AllowUnsorted="false">
    <NoRecordsContent>
        <MudText Typo="Typo.body1">No tracks found.</MudText>
    </NoRecordsContent>
    <LoadingContent>
        <MudText Typo="Typo.body1">Loading tracks…</MudText>
    </LoadingContent>
    <HeaderContent>
        <MudTh Style="width: 1%; white-space: nowrap;">Track #</MudTh>
        <MudTh Style="width: 1%; white-space: nowrap;">Art</MudTh>
        <MudTh><MudTableSortLabel SortLabel="TrackName" T="TrackDto" InitialDirection="SortDirection.Ascending">Track Name</MudTableSortLabel></MudTh>
        <MudTh><MudTableSortLabel SortLabel="Artist" T="TrackDto">Artist</MudTableSortLabel></MudTh>
        <MudTh><MudTableSortLabel SortLabel="Album" T="TrackDto">Album</MudTableSortLabel></MudTh>
        <MudTh><MudTableSortLabel SortLabel="Genre" T="TrackDto">Genre</MudTableSortLabel></MudTh>
        <MudTh><MudTableSortLabel SortLabel="ReleaseDate" T="TrackDto">Release Date</MudTableSortLabel></MudTh>
        <MudTh Style="width: 1%; white-space: nowrap;">Waveform</MudTh>
        <MudTh Style="width: 1%; white-space: nowrap;">Actions</MudTh>
    </HeaderContent>
    <RowTemplate>
        <MudTd DataLabel="Track #">@context.TrackNumber</MudTd>
        <MudTd DataLabel="Art">
            @if (!string.IsNullOrEmpty(context.Release?.ImagePath))
            {
                <div class="cms-track-thumb"
                     style="background-image: url('@ThumbUrl(context.Release.ImagePath)');"></div>
            }
            else
            {
                <div class="cms-track-thumb cms-track-thumb--fallback"></div>
            }
        </MudTd>
        <MudTd DataLabel="Track Name">@context.TrackName</MudTd>
        <MudTd DataLabel="Artist">@(context.Release?.Artist ?? "—")</MudTd>
        <MudTd DataLabel="Album">@(context.Release?.Title ?? "—")</MudTd>
        <MudTd DataLabel="Genre">@(context.Release?.Genre ?? "—")</MudTd>
        <MudTd DataLabel="Release Date">@(context.Release?.ReleaseDate?.ToString("d MMMM, yyyy") ?? "—")</MudTd>
        <MudTd DataLabel="Waveform">
            @if (HasProfile(context.EntryKey))
            {
                <MudIcon Icon="@Icons.Material.Filled.CheckCircle" Color="Color.Success" Size="Size.Small" />
            }
            else
            {
                <MudIcon Icon="@Icons.Material.Filled.Cancel" Color="Color.Warning" Size="Size.Small" />
            }
        </MudTd>
        <MudTd DataLabel="Actions">
            <MudTooltip Text="Edit">
                <MudIconButton Icon="@Icons.Material.Filled.Edit"
                               Size="Size.Small"
                               Color="Color.Primary"
                               Href="@($"/tracks/{context.Id}/edit")" />
            </MudTooltip>
            <MudTooltip Text="Delete">
                <MudIconButton Icon="@Icons.Material.Filled.Delete"
                               Size="Size.Small"
                               Color="Color.Error"
                               OnClick="@(() => ConfirmAndDelete(context))" />
            </MudTooltip>
            <MudTooltip>
                <TooltipContent>
                    <div class="cms-track-info">
                        <div>Entry: @context.EntryKey</div>
                        <div>File: @(context.OriginalFileName ?? "—")</div>
                    </div>
                </TooltipContent>
                <ChildContent>
                    <MudIconButton Icon="@Icons.Material.Outlined.Info" Size="Size.Small" />
                </ChildContent>
            </MudTooltip>
            @if (!HasProfile(context.EntryKey))
            {
                <MudTooltip Text="Generate Waveform">
                    <MudIconButton Icon="@Icons.Material.Filled.GraphicEq"
                                   Size="Size.Small"
                                   Color="Color.Secondary"
                                   Disabled="@(_bulkRunning || _generating.Contains(context.EntryKey))"
                                   OnClick="@(() => GenerateOneAsync(context))" />
                </MudTooltip>
            }
        </MudTd>
    </RowTemplate>
    <PagerContent>
        <MudTablePager PageSizeOptions="new[] { 10, 20, 50 }" />
    </PagerContent>
</MudTable>

@code {
    [Parameter] public string? AlbumFilter { get; set; }
    [Parameter] public string? GenreFilter { get; set; }
    [Parameter] public bool ShowAddButton { get; set; } = true;
    [Parameter] public int PageSize { get; set; } = 20;
    [Parameter] public EventCallback OnTracksChanged { get; set; }
    [Parameter] public EventCallback OnStatusLoaded { get; set; }

    private MudTable<TrackDto>? _table;

    // EntryKey → HasProfile. Loaded once on init; per-row generate flips a single entry to true.
    private Dictionary<string, bool> _waveformStatus = new();
    private readonly HashSet<string> _generating = new();

    // The parent owns "Generate All Missing"; while it runs it disables this grid's per-row buttons.
    private bool _bulkRunning;

    protected override async Task OnInitializedAsync()
    {
        await RefreshWaveformStatusAsync();
    }

    private bool HasProfile(string entryKey) =>
        _waveformStatus.TryGetValue(entryKey, out var hasProfile) && hasProfile;

    // Relative path — resolves against the Manager's own origin, proxied by ImageProxyController.
    private static string ThumbUrl(string imagePath) =>
        $"/api/image/{Uri.EscapeDataString(imagePath)}";

    /// <summary>Number of tracks with a missing waveform profile — drives the parent's bulk button label.</summary>
    public int GetMissingCount() => _waveformStatus.Count(kv => !kv.Value);

    /// <summary>
    /// Reload the full waveform-status map. Called on init and by the parent after a bulk generate so
    /// the per-row icons reflect the new state.
    /// </summary>
    public async Task RefreshWaveformStatusAsync()
    {
        var result = await CmsTrackService.GetWaveformStatusAsync();
        _waveformStatus = result.Success && result.Value is not null
            ? result.Value.ToDictionary(s => s.EntryKey, s => s.HasProfile)
            : new Dictionary<string, bool>();

        StateHasChanged();
        await OnStatusLoaded.InvokeAsync();
    }

    /// <summary>Set by the parent while its bulk generate runs so per-row buttons disable.</summary>
    public void SetBulkRunning(bool running)
    {
        _bulkRunning = running;
        StateHasChanged();
    }

    private async Task<TableData<TrackDto>> LoadServerData(TableState state, CancellationToken cancellationToken)
    {
        var pageNumber = state.Page + 1; // MudTable is 0-based, service is 1-based.
        var sortColumn = string.IsNullOrEmpty(state.SortLabel) ? "TrackName" : state.SortLabel;
        var sortDescending = state.SortDirection == SortDirection.Descending;

        var result = await CmsTrackService.GetPagedAsync(
            pageNumber, state.PageSize, sortColumn, sortDescending,
            AlbumFilter, GenreFilter, cancellationToken);

        if (!result.Success || result.Value is null)
        {
            var errorText = result.Messages.FirstOrDefault()?.Message ?? "Unknown error";
            Snackbar.Add($"Failed to load tracks: {errorText}", Severity.Error);
            return new TableData<TrackDto> { Items = Array.Empty<TrackDto>(), TotalItems = 0 };
        }

        var page = result.Value;
        return new TableData<TrackDto>
        {
            Items = page.Items,
            TotalItems = page.TotalCount
        };
    }

    private async Task ConfirmAndDelete(TrackDto track)
    {
        var confirmed = await DialogService.ShowMessageBox(
            title: "Delete track",
            markupMessage: new MarkupString($"Delete <strong>{WebUtility.HtmlEncode(track.TrackName)}</strong> by {WebUtility.HtmlEncode(track.Release?.Artist ?? "Unknown")}? This removes both the metadata row and the underlying audio entry."),
            yesText: "Delete",
            cancelText: "Cancel");

        if (confirmed != true) return;

        try
        {
            var result = await CmsTrackService.DeleteTrackAsync(track.Id);
            if (result.Success)
            {
                Snackbar.Add($"Deleted '{track.TrackName}'.", Severity.Success);
                if (_table is not null) await _table.ReloadServerData();
                await OnTracksChanged.InvokeAsync();
            }
            else
            {
                var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error";
                Snackbar.Add($"Delete failed: {error}", Severity.Error);
            }
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Delete failed for track {TrackId}", track.Id);
            Snackbar.Add("Delete failed — please try again.", Severity.Error);
        }
    }

    private async Task GenerateOneAsync(TrackDto track)
    {
        _generating.Add(track.EntryKey);
        StateHasChanged();
        try
        {
            var result = await CmsTrackService.GenerateWaveformProfileAsync(track.EntryKey);
            if (result.Success)
            {
                _waveformStatus[track.EntryKey] = true;
                Snackbar.Add($"Generated profile for '{track.TrackName}'.", Severity.Success);
            }
            else
            {
                var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error";
                Snackbar.Add($"Generate failed for '{track.TrackName}': {error}", Severity.Error);
            }
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Waveform generation failed for {EntryKey}", track.EntryKey);
            Snackbar.Add($"Generate failed for '{track.TrackName}' — please try again.", Severity.Error);
        }
        finally
        {
            _generating.Remove(track.EntryKey);
            StateHasChanged();
        }
    }
}
