@page "/tracks/{Id:long}"
@using DeepDrftManager.Services
@using DeepDrftModels.Enums
@using Microsoft.AspNetCore.Components.Forms
@attribute [Authorize]
@inject ICmsTrackService CmsTrackService
@inject CmsTrackBrowserViewModel VM
@inject ISnackbar Snackbar
@inject IDialogService DialogService
@inject NavigationManager Nav
@inject ILogger<TrackEdit> Logger

<PageTitle>Edit Track — DeepDrft CMS</PageTitle>

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

    @if (_loading)
    {
        <MudProgressCircular Indeterminate="true" />
    }
    else if (_track is null)
    {
        <MudAlert Severity="Severity.Warning">
            Track not found.
        </MudAlert>
    }
    else
    {
        <MudText Typo="Typo.h4" GutterBottom="true">Edit Track</MudText>

        <MudPaper Class="pa-6" Elevation="2">
            <MudStack Spacing="4">
                <MudField Label="Entry Key" Variant="Variant.Outlined" InnerPadding="false">
                    <MudText Typo="Typo.body1" Style="font-family: monospace;">@_track.EntryKey</MudText>
                    <MudText Typo="Typo.caption" Color="Color.Default">
                        Vault reference — not editable.
                    </MudText>
                </MudField>

                <MudTextField @bind-Value="_form.TrackName"
                              Label="Track Name"
                              Required="true"
                              RequiredError="Track name is required"
                              Variant="Variant.Outlined" />

                <MudTextField @bind-Value="_form.Artist"
                              Label="Artist"
                              Required="true"
                              RequiredError="Artist is required"
                              Variant="Variant.Outlined" />

                <MudTextField @bind-Value="_form.Album"
                              Label="Album"
                              Variant="Variant.Outlined" />

                <MudTextField @bind-Value="_form.Genre"
                              Label="Genre"
                              Variant="Variant.Outlined" />

                <MediumFields @bind-Medium="_form.Medium" @bind-ReleaseType="_form.ReleaseType" Disabled="_busy" />

                <MudNumericField @bind-Value="_form.TrackNumber"
                                 Label="Track Number"
                                 Min="1"
                                 Variant="Variant.Outlined" />

                <MudField Label="Cover Art" Variant="Variant.Outlined" InnerPadding="false">
                    <MudStack Spacing="3">
                        @if (ImagePreviewUrl is { } previewUrl)
                        {
                            <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
                                <MudImage Src="@previewUrl"
                                          Alt="Cover art preview"
                                          Elevation="1"
                                          Style="max-width: 120px; height: auto; border-radius: 4px;" />
                                <MudIconButton Icon="@Icons.Material.Filled.Clear"
                                               Color="Color.Error"
                                               Size="Size.Small"
                                               Disabled="_busy"
                                               OnClick="ClearImage"
                                               aria-label="Clear cover art" />
                            </MudStack>
                        }
                        else if (_selectedImageFile is not null)
                        {
                            <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
                                <MudText Typo="Typo.body2" Color="Color.Default">New image selected (not yet saved).</MudText>
                                <MudIconButton Icon="@Icons.Material.Filled.Clear"
                                               Color="Color.Error"
                                               Size="Size.Small"
                                               Disabled="_busy"
                                               OnClick="ClearImage"
                                               aria-label="Cancel image selection" />
                            </MudStack>
                        }
                        else
                        {
                            <MudText Typo="Typo.body2" Color="Color.Default">No cover art set.</MudText>
                        }

                        <InputFile OnChange="HandleImageFileSelected" accept="image/*" />
                        @if (_selectedImageFile is { } selected)
                        {
                            <MudText Typo="Typo.caption">Selected: @selected.Name (will upload on save)</MudText>
                        }
                    </MudStack>
                </MudField>

                <MudDatePicker @bind-Date="_form.ReleaseDate"
                               Label="Release Date"
                               DateFormat="yyyy-MM-dd"
                               Variant="Variant.Outlined" />

                <MudStack Row="true" Spacing="2" Justify="Justify.SpaceBetween">
                    <MudButton Variant="Variant.Filled"
                               Color="Color.Error"
                               StartIcon="@Icons.Material.Filled.Delete"
                               Disabled="_busy"
                               OnClick="ConfirmDelete">
                        Delete
                    </MudButton>

                    <MudButton Variant="Variant.Filled"
                               Color="Color.Primary"
                               StartIcon="@Icons.Material.Filled.Save"
                               Disabled="_busy || !CanSave"
                               OnClick="SaveAsync">
                        Save Changes
                    </MudButton>
                </MudStack>
            </MudStack>
        </MudPaper>
    }
</MudContainer>

@code {
    [Parameter] public long Id { get; set; }

    private TrackDto? _track;
    private TrackEditForm _form = new();
    private bool _loading = true;
    private bool _busy;
    private IBrowserFile? _selectedImageFile;

    private bool CanSave =>
        !string.IsNullOrWhiteSpace(_form.TrackName)
        && !string.IsNullOrWhiteSpace(_form.Artist);

    // Relative path — resolves against the Manager's own origin, proxied by ImageProxyController.
    private string? ImagePreviewUrl =>
        string.IsNullOrEmpty(_form.ImagePath)
            ? null
            : $"/api/image/{Uri.EscapeDataString(_form.ImagePath)}";

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

    private async Task LoadAsync()
    {
        _loading = true;
        var result = await CmsTrackService.GetByIdAsync(Id);
        _track = result.Success ? result.Value : null;
        if (_track is not null)
        {
            _form = TrackEditForm.From(_track);
        }
        _loading = false;
    }

    private async Task SaveAsync()
    {
        if (_track is null || !CanSave) return;

        _busy = true;
        try
        {
            // Upload any newly picked cover art first; abort the save if it fails so we never
            // persist metadata pointing at an image that was never stored.
            if (_selectedImageFile is { } file)
            {
                await using var imageStream = file.OpenReadStream(maxAllowedSize: 50_000_000);
                var uploadResult = await CmsTrackService.UploadImageAsync(
                    imageStream, file.Name, file.ContentType);
                if (!uploadResult.Success)
                {
                    var uploadError = uploadResult.Messages.FirstOrDefault()?.Message ?? "Unknown error";
                    Snackbar.Add($"Image upload failed: {uploadError}", Severity.Error);
                    return;
                }
                _form.ImagePath = uploadResult.Value;
                _selectedImageFile = null;
            }

            // Metadata update over HTTP — EntryKey is immutable and not sent. The Content API
            // loads the authoritative row and applies these fields. imagePath is tri-state: an
            // explicit empty string clears the link, a value sets it.
            var releaseDate = _form.ReleaseDate is { } d ? DateOnly.FromDateTime(d) : (DateOnly?)null;
            var updated = await CmsTrackService.UpdateAsync(
                Id, _form.TrackName, _form.Artist,
                string.IsNullOrWhiteSpace(_form.Album) ? null : _form.Album,
                string.IsNullOrWhiteSpace(_form.Genre) ? null : _form.Genre,
                releaseDate,
                string.IsNullOrEmpty(_form.ImagePath) ? "" : _form.ImagePath,
                _form.ReleaseType,
                _form.Medium,
                _form.TrackNumber);
            if (updated.Success)
            {
                // Album/genre browse lists derive from this track's metadata; drop their cache so
                // the /tracks browser re-fetches fresh data on next mode switch.
                VM.Invalidate();
                Snackbar.Add("Track updated.", Severity.Success);
                await LoadAsync();
            }
            else
            {
                var error = updated.Messages.FirstOrDefault()?.Message ?? "Unknown error";
                Snackbar.Add($"Save failed: {error}", Severity.Error);
            }
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Save failed for track {TrackId}", Id);
            Snackbar.Add("Save failed — please try again.", Severity.Error);
        }
        finally
        {
            _busy = false;
        }
    }

    private void HandleImageFileSelected(InputFileChangeEventArgs e)
    {
        _selectedImageFile = e.File;
    }

    private void ClearImage()
    {
        _form.ImagePath = null;
        _selectedImageFile = null;
    }

    private async Task ConfirmDelete()
    {
        if (_track is null) return;

        var confirmed = await DialogService.ShowMessageBox(
            "Delete track",
            $"Permanently delete \"{_track.TrackName}\" by {_track.Release?.Artist ?? "Unknown"}? This cannot be undone.",
            yesText: "Delete",
            cancelText: "Cancel");

        if (confirmed != true) return;

        _busy = true;
        try
        {
            var result = await CmsTrackService.DeleteTrackAsync(Id);
            if (result.Success)
            {
                // Deleting a track can empty or alter a release; drop the browse cache so the
                // /tracks album and genre lists re-fetch fresh counts on next mode switch.
                VM.Invalidate();
                Snackbar.Add("Track deleted.", Severity.Success);
                Nav.NavigateTo("/tracks");
            }
            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}", Id);
            Snackbar.Add("Delete failed — please try again.", Severity.Error);
        }
        finally
        {
            _busy = false;
        }
    }

    private sealed class TrackEditForm
    {
        public string TrackName { get; set; } = string.Empty;
        public string Artist { get; set; } = string.Empty;
        public string? Album { get; set; }
        public string? Genre { get; set; }
        public string? ImagePath { get; set; }
        public DateTime? ReleaseDate { get; set; }
        public ReleaseType ReleaseType { get; set; } = ReleaseType.Single;

        // Drives ReleaseType visibility via MediumFields and is persisted on save (PUT api/track/meta
        // carries Medium). A non-Cut medium resets ReleaseType to its default server-side.
        public ReleaseMedium Medium { get; set; } = ReleaseMedium.Cut;
        public int TrackNumber { get; set; } = 1;

        public static TrackEditForm From(TrackDto track) => new()
        {
            TrackName = track.TrackName,
            Artist = track.Release?.Artist ?? string.Empty,
            Album = track.Release?.Title,
            Genre = track.Release?.Genre,
            ImagePath = track.Release?.ImagePath,
            ReleaseDate = track.Release?.ReleaseDate is { } d
                ? d.ToDateTime(TimeOnly.MinValue)
                : null,
            ReleaseType = track.Release?.ReleaseType ?? ReleaseType.Single,
            Medium = track.Release?.Medium ?? ReleaseMedium.Cut,
            TrackNumber = track.TrackNumber
        };
    }
}
