@page "/ispezione"
@using Microsoft.Extensions.Logging
@using SteUp.Shared.Components.Layout
@using SteUp.Shared.Components.Layout.Overlay
@using SteUp.Shared.Components.SingleElements.Card
@using SteUp.Shared.Components.SingleElements.MessageBox
@using SteUp.Shared.Core.Dto
@using SteUp.Shared.Core.Entities
@using SteUp.Shared.Core.Enum
@using SteUp.Shared.Core.Interface.IntegryApi
@using SteUp.Shared.Core.Interface.LocalDb
@using SteUp.Shared.Core.Interface.System
@using SteUp.Shared.Core.Messages.Ispezione
@using SteUp.Shared.Core.Messages.Scheda
@inject NewSchedaService NewScheda
@inject CompleteInspectionService CompleteInspection
@inject IIspezioniService IspezioniService
@inject IDialogService Dialog
@inject IIntegrySteupService IntegrySteupService
@inject IFileManager FileManager
@inject ILogger<IspezionePage> Logger
@implements IDisposable

<HeaderLayout Title="Ispezione" BackTo="Indietro" Back="true"/>

<div class="container content pb-safe-area ispezione">
    <InspectionCard Ispezione="SteupDataService.InspectionPageState.Ispezione"/>

    @if (!SchedeGrouped.IsNullOrEmpty())
    {
        <MudExpansionPanels MultiExpansion="true">
            @{
                var panelIndex = 0;
            }
            @foreach (var group in SchedeGrouped)
            {
                var isFirstPanel = panelIndex == 0;
                panelIndex++;
                <MudExpansionPanel Class="expansion-panel" Expanded="isFirstPanel" Text="@group.Key.Descrizione">
                    <TitleContent>
                        @{
                            var daInviare = group.Value.CountDaInviare();
                        }
                        <div class="header-scheda-group">
                            <div class="title">
                                <MudText Typo="Typo.h6"><b>@group.Key.Descrizione</b></MudText>
                                <MudChip T="string" Size="Size.Small" Color="Color.Default">
                                    @($"{group.Value.Count} sched{(group.Value.Count == 1 ? "a" : "e")}")
                                </MudChip>
                                @if (daInviare > 0)
                                {
                                    <MudChip T="string" Size="Size.Small" Variant="Variant.Filled"
                                             Color="Color.Primary" Icon="@Icons.Material.Rounded.PhonelinkOff">
                                        @($"{daInviare} da inviare")
                                    </MudChip>
                                }
                            </div>
                            @if (SteupDataService.InspectionPageState.Ispezione.Stato != StatusEnum.Completata)
                            {
                                <div class="action-scheda-group">
                                    <MudFab StartIcon="@Icons.Material.Rounded.Add"
                                            Color="Color.Default" Size="Size.Medium"
                                            Disabled="!NetworkService.IsNetworkAvailable()"
                                            aria-label="@($"Nuova scheda su {group.Key.Descrizione}")"
                                            OnClick="@(() => CreateNewScheda(group.Key))"/>

                                    @if (NetworkService.IsNetworkAvailable() && daInviare > 0)
                                    {
                                        <MudFab StartIcon="@Icons.Material.Rounded.CloudUpload" Label="Esporta reparto"
                                                Color="Color.Primary" Size="Size.Medium"
                                                aria-label="@($"Esporta il reparto {group.Key.Descrizione} al server")"
                                                OnClick="@(() => ExportReparto(group.Key))"/>
                                    }
                                </div>
                            }
                        </div>
                    </TitleContent>
                    <ChildContent>
                        @foreach (var scheda in group.Value)
                        {
                            <SchedaCard Scheda="scheda" OnSchedaDeleted="OnSchedaDeleted"
                                        OnSchedaModified="OnSchedaModified"
                                        Ispezione="@SteupDataService.InspectionPageState.Ispezione"/>
                        }
                    </ChildContent>
                </MudExpansionPanel>
            }
        </MudExpansionPanels>
    }
    else
    {
        <div class="empty-state">
            <MudIcon Icon="@Icons.Material.Rounded.AssignmentLate" Class="empty-state-icon" Size="Size.Large"/>
            <p class="empty-state-title">Nessuna scheda ancora</p>
            @if (SteupDataService.InspectionPageState.Ispezione.Stato != StatusEnum.Completata)
            {
                <p class="empty-state-text">
                    Tocca <b>+</b> in basso per creare la prima scheda di questa ispezione.
                </p>
            }
        </div>
    }
</div>

<SpinnerOverlay VisibleOverlay="VisibleOverlay" SuccessAnimation="_success" Message="@_progressMessage"/>
<ConfirmMessageBox @ref="_exportRepartoBox" NoText="Annulla" YesText="Esporta" YesColor="Color.Primary"
                   Message="Le schede di questo reparto verranno inviate al server. Procedere?"/>

@code {
    private List<Scheda> SchedeList { get; set; } = [];
    private Dictionary<JtbFasiDto, List<Scheda>> SchedeGrouped { get; set; } = [];

    private bool VisibleOverlay { get; set; }
    private bool _isBusy;
    private bool _success;
    private string? _progressMessage;

    private ConfirmMessageBox _exportRepartoBox = null!;

    protected override void OnInitialized()
    {
        NewScheda.OnNewScheda += LoadSchede;
        CompleteInspection.OnComplete += HandleCompleteInspection;

        LoadSchede();
    }

    private void LoadSchede()
    {
        var ispezione = SteupDataService.InspectionPageState.Ispezione;

        InvokeAsync(async () =>
        {
            SchedeList = await IspezioniService.GetAllSchedeOfIspezioneAsync(
                ispezione.CodMdep, ispezione.Data, ispezione.Rilevatore
            );

            GroupSchede();
            StateHasChanged();
        });
    }

    private async void HandleCompleteInspection()
    {
        // Guardia anti doppio-invio: il completamento è irreversibile.
        if (_isBusy) return;
        _isBusy = true;

        try
        {
            await InvokeAsync(() =>
            {
                VisibleOverlay = true;
                StateHasChanged();
            });

            var ispezione = SteupDataService.InspectionPageState.Ispezione;

            var daInviare = ispezione.Schede.Where(x => x.ActivityId == null).ToList();
            var totale = daInviare.Count;
            var indice = 0;
            var fallite = 0;

            foreach (var scheda in daInviare)
            {
                indice++;
                await SetProgress($"Invio scheda {indice} di {totale}…");

                var apiResponse = await IntegrySteupService.SaveScheda(
                    new SaveRequestDto
                    {
                        LocalIdScheda = scheda.Id,
                        ActivityTypeId = scheda.ActivityTypeId,
                        CodJfas = scheda.CodJfas,
                        CodMdep = ispezione.CodMdep,
                        DataCreazione = ispezione.Data,
                        Note = scheda.Note,
                        PersonaRif = scheda.Responsabile,
                        Barcodes = scheda.Articoli.ConvertAll(x => x.Barcode),
                        Scandeza = (ScadenzaEnum)scheda.Scadenza,
                        // Aggancia all'ispezione esistente: dopo la prima scheda l'id e' noto,
                        // così le successive non creano nuove ispezioni.
                        ParentActivityId = ispezione.ActivityId
                    }
                );

                // Fallita: resta "Da inviare". Non completeremo l'ispezione finché tutte non sono arrivate.
                if (apiResponse == null)
                {
                    fallite++;
                    continue;
                }

                scheda.ActivityId = apiResponse.ActivityIdScheda;
                await IspezioniService.UpdateSchedaAsync(scheda);

                await IspezioniService.UpdateActivityIdIspezioneAsync(
                    ispezione.CodMdep,
                    ispezione.Data,
                    ispezione.Rilevatore,
                    apiResponse.ActivityIdIspezione
                );
                // Aggiorna l'id in memoria per l'iterazione successiva.
                ispezione.ActivityId = apiResponse.ActivityIdIspezione;

                if (scheda.ImageNames == null) continue;

                var fileList = (await FileManager.GetInspectionFiles(ispezione, scheda.ImageNames))?
                    .Where(x => x.ToUpload).ToList();

                if (fileList == null) continue;

                var totFoto = fileList.Count;
                var indiceFoto = 0;

                foreach (var file in fileList)
                {
                    indiceFoto++;
                    await SetProgress($"Scheda {indice}/{totale} · foto {indiceFoto}/{totFoto}…");
                    await IntegrySteupService.UploadFile(scheda.ActivityId!, file.FileBytes!, file.Name!);
                }
            }

            // Integrità dati: se anche una sola scheda non è arrivata al server, NON completare.
            // L'ispezione resta editabile e le schede fallite restano "Da inviare".
            if (fallite > 0)
            {
                await InvokeAsync(() =>
                {
                    _progressMessage = null;
                    StateHasChanged();
                });

                LoadSchede(); // rinfresca i badge: riuscite → "Inviato", fallite → restano "Da inviare"

                await Dialog.ShowWarning(
                    fallite == 1
                        ? "1 scheda non è stata inviata e resta salvata sul dispositivo. Controlla la connessione e riprova prima di concludere l'ispezione."
                        : $"{fallite} schede non sono state inviate e restano salvate sul dispositivo. Controlla la connessione e riprova prima di concludere l'ispezione."
                );
                return;
            }

            await SetProgress("Completamento ispezione…");

            await IntegrySteupService.CompleteInspection(ispezione.ActivityId!);
            await IspezioniService.UpdateStatoIspezioneAsync(
                ispezione.CodMdep,
                ispezione.Data,
                ispezione.Rilevatore,
                StatusEnum.Completata
            );

            SteupDataService.InspectionPageState.Ispezione.Stato = StatusEnum.Completata;

            // Riscontro al momento più importante: la spunta di successo prima di chiudere l'overlay.
            await InvokeAsync(() =>
            {
                _progressMessage = "Ispezione inviata";
                _success = true;
                StateHasChanged();
            });
            await Task.Delay(1800);
        }
        catch (Exception e)
        {
            OnError(e, e.Message);
        }
        finally
        {
            _isBusy = false;
            _success = false;
            _progressMessage = null;
            await InvokeAsync(() =>
            {
                VisibleOverlay = false;
                StateHasChanged();
            });
        }
    }

    private Task SetProgress(string message) =>
        InvokeAsync(() =>
        {
            _progressMessage = message;
            StateHasChanged();
        });

    private void GroupSchede()
    {
        SchedeGrouped = SchedeList
            .Where(s => s.Reparto != null)
            .GroupBy(s => s.CodJfas)
            .ToDictionary(
                g => g.First().Reparto!,
                g => g.ToList()
            );
    }

    private void OnSchedaModified(Scheda obj)
    {
        var index = SchedeList.FindIndex(x => x.Id.Equals(obj.Id));
        if (index >= 0) SchedeList[index] = obj;

        GroupSchede();
        StateHasChanged();
    }

    private void OnSchedaDeleted(Scheda obj)
    {
        SchedeList.Remove(obj);
        GroupSchede();
        StateHasChanged();
    }

    private async Task CreateNewScheda(JtbFasiDto jtbFasi)
    {
        var modal = await Dialog.OpenFormScheda(
            SteupDataService.InspectionPageState.Ispezione.CodMdep,
            SteupDataService.InspectionPageState.Ispezione.Data,
            true,
            new Scheda { Reparto = jtbFasi }
        );

        if (modal is { Canceled: false }) LoadSchede();
    }

    private async Task ExportReparto(JtbFasiDto jtbFasi)
    {
        // Guardia anti doppio-tap: un secondo tocco durante l'invio non ri-esporta il batch.
        if (_isBusy) return;

        var confirmed = await _exportRepartoBox.ShowAsync();
        if (confirmed is not true) return;

        _isBusy = true;
        VisibleOverlay = true;
        StateHasChanged();

        try
        {
            var ispezione = SteupDataService.InspectionPageState.Ispezione;

            var saveRequest = SchedeGrouped[jtbFasi].ConvertAll(x =>
            {
                return new SaveRequestDto
                {
                    LocalIdScheda = x.Id,
                    ActivityTypeId = x.ActivityTypeId,
                    CodJfas = x.CodJfas,
                    CodMdep = ispezione.CodMdep,
                    DataCreazione = ispezione.Data,
                    Note = x.Note,
                    PersonaRif = x.Responsabile,
                    Barcodes = x.Articoli.ConvertAll(y => y.Barcode),
                    Scandeza = (ScadenzaEnum)x.Scadenza,
                    // Aggancia all'ispezione esistente sul server (evita di crearne una nuova a ogni export).
                    ParentActivityId = ispezione.ActivityId
                };
            });

            var apiResponse = await IntegrySteupService.SaveMultipleSchede(saveRequest);

            if (apiResponse == null)
            {
                Snackbar.Add("Esportazione non riuscita. Le schede restano sul dispositivo, riprova.", Severity.Error);
                return;
            }

            SteupDataService.InspectionPageState.Ispezione.ActivityId = apiResponse.ActivityIdIspezione;

            await IspezioniService.UpdateActivityIdIspezioneAsync(ispezione.CodMdep, ispezione.Data,
                UserSession.User.Username, apiResponse.ActivityIdIspezione
            );

            if (!apiResponse.ActivityIdSchedaList.IsNullOrEmpty())
            {
                foreach (var scheda in SchedeGrouped[jtbFasi])
                {
                    var activityId = apiResponse.ActivityIdSchedaList!.Find(x =>
                        x.LocalId != null && x.LocalId == scheda.Id
                    )?.ActivityId;

                    if (activityId == null) continue;

                    scheda.ActivityId = activityId;
                    await IspezioniService.UpdateActivityIdSchedaAsync(scheda.Id, scheda.ActivityId);
                }
            }

            Snackbar.Add("Reparto esportato", Severity.Success);
        }
        catch (Exception e)
        {
            OnError(e, e.Message);
        }
        finally
        {
            _isBusy = false;
            VisibleOverlay = false;
            StateHasChanged();
        }
    }

    private void OnError(Exception? e, string? technicalMessage)
    {
        // Il dettaglio tecnico va nei log, non davanti al rilevatore in campo.
        if (e != null) Logger.LogError(e, technicalMessage);

        _ = Dialog.ShowError(
            "Invio non riuscito. Il lavoro resta salvato sul dispositivo: controlla la connessione e riprova."
        );
    }

    void IDisposable.Dispose()
    {
        NewScheda.OnNewScheda -= LoadSchede;
        CompleteInspection.OnComplete -= HandleCompleteInspection;
    }

}