@page "/expeditions/create"
@using Blazored.Typeahead
@using Domain.Dtos.Stock
@using Services.Lookups
@using Services.Stock.Expeditions
@using System.Text.Json
@using phronCare.UIBlazor.Pages.Stock.Shared

@inject NavigationManager Navigation
@inject ExpeditionService expeditionService
@inject ISalesLookupService lookUpService
@inject IToastService toastService
@inject IModalService Modal

<EditForm Model="Model" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div class="card mt-4" style="zoom:80%">
        <div class="card-header d-flex justify-content-center align-items-center">
            <h3 class="card-title m-0">Nueva Expedición</h3>
        </div>

        <div class="card-body">
            <div class="row mb-3">
                <div class="col-md-6">
                    <label class="form-label">Presupuesto aprobado</label>
                    <BlazoredTypeahead id="quotes" TItem="ELookUpItem" TValue="ELookUpItem"
                                       SearchMethod="SearchQuotes"
                                       Value="SelectedQuote"
                                       ValueChanged="OnQuoteSelected"
                                       ValueExpression="@(() => SelectedQuote)"
                                       MaximumSuggestions="10"
                                       Placeholder="Buscar presupuesto aprobado..."
                                       TextProperty="Nombre">
                        <ResultTemplate Context="item">
                            @item.Nombre
                        </ResultTemplate>
                        <SelectedTemplate Context="item">
                            @item.Nombre
                        </SelectedTemplate>
                    </BlazoredTypeahead>
                </div>
                <div class="col-md-4">
                    <label class="form-label">Destinatario</label>
                    <InputText class="form-control" @bind-Value="Model.RecipientName" />
                </div>
                <div class="col-md-2">
                    <label class="form-label">Ticket ID</label>
                    <InputText class="form-control" @bind-Value="ticketIdString" />
                </div>
            </div>

            <div class="row mb-3">
                <div class="col-md-4">
                    <label class="form-label">Profesional</label>
                    <InputText class="form-control" @bind-Value="ExtraInfo.Professional" />
                </div>
                <div class="col-md-4">
                    <label class="form-label">Institución</label>
                    <InputText class="form-control" @bind-Value="ExtraInfo.Institution" />
                </div>
                <div class="col-md-4">
                    <label class="form-label">Paciente</label>
                    <InputText class="form-control" @bind-Value="ExtraInfo.Patient" />
                </div>
            </div>

            <div class="row mb-3">
                <div class="col-md-4">
                    <label class="form-label">Fecha de Cirugía</label>
                    <InputDate class="form-control" @bind-Value="ExtraInfo.SurgeryDate" />
                </div>
                <div class="col-md-8">
                    <label class="form-label">Observaciones</label>
                    <InputTextArea class="form-control" @bind-Value="Model.Observations" />
                </div>
            </div>

            @if (!string.IsNullOrWhiteSpace(DispatchInstruction))
            {
                <div class="alert alert-info">
                    <strong>Instrucciones desde presupuesto:</strong><br />
                    @DispatchInstruction
                </div>
            }
        </div>
    </div>

    <div class="card mt-3">
        <div class="card-header d-flex justify-content-between align-items-center">
            <h5 class="card-title m-0">Productos a Expedir</h5>
            <div class="btn-group">
                <button class="btn btn-dark btn-sm" title="Agregar producto" @onclick="OpenStockItemSelectorModal">
                    <i class="fas fa-box"></i> Producto
                </button>
                <button class="btn btn-dark btn-sm" disabled title="Agregar set">
                    <i class="fas fa-th-large"></i> Set-Box
                </button>
                <button class="btn btn-dark btn-sm" disabled title="Escanear producto">
                    <i class="fas fa-barcode"></i> Scanner
                </button>
            </div>
        </div>

        <div class="card-body p-2">
            @if (Details.Any())
            {
                <div class="expedition-table-wrap" style="zoom:80%">
                    <table class="table table-sm table-bordered expedition-table">
                        <thead class="table-light">
                            <tr>
                                <th class="text-center align-middle">Producto</th>
                                <th>Nombre</th>
                                <th class ="text-center align-middle">Cant.</th>
                                <th class="text-center align-middle">Lote</th>
                                <th class="text-center align-middle">Serial</th>
                                <th class="text-center align-middle">Vencimiento</th>
                                <th class="text-center align-middle">Ubicación</th>
                                <th style="width: 40px;"></th>
                            </tr>
                        </thead>
                        <tbody>
                        @foreach (var item in Details)
                        {
                            <tr>
                                <td class="text-center align-middle">@item.ProductId</td>
                                <td>@item.ProductName</td>
                                <td class="text-center align-middle">@item.Quantity</td>
                                <td class="text-center align-middle">@item.Batch</td>
                                <td class="text-center align-middle">@item.Serial</td>
                                <td class="text-center align-middle">@item.Expiration?.ToString("yyyy-MM-dd")</td>
                                <td class ="text-center align-middle">@item.LocationId</td>
                                <td class="text-center align-middle">
                                    <button class="btn btn-link p-0" style="color: red;" title="Eliminar" @onclick="() => RemoveItem(item)">
                                        <i class="fas fa-trash"></i>
                                    </button>
                                </td>
                            </tr>
                        }
                        </tbody>
                    </table>
                </div>
            }
            else
            {
                <p class="text-muted">No hay productos agregados.</p>
            }
        </div>
    </div>

    <div class="mt-3 d-flex justify-content-end">
        <button class="btn btn-primary"
                @onclick="SaveAsync"
                disabled="@IsSaving">
            @if (IsSaving)
            {
                <span class="spinner-border spinner-border-sm me-2"></span>
            }
            Guardar Expedición
        </button>
    </div>

</EditForm>

@code {
    private ELSExpeditionHeader Model = new()
    {
        Issuedate = DateTime.Today,
        LocationId = 1, // Depósito por defecto
        OriginType = "surgery", // Tipo de origen por defecto
        Printcount = 0
        // mapear otros campos de cabecera si aplica (BU, moneda, etc.)
    };
    private ExtraInfoModel ExtraInfo = new();
    private ELookUpItem? SelectedQuote;

    private List<ELSExpeditionDetail> Details = new();
    private List<ProductSetItemDto> ProductSetItems = new();

    private string DispatchInstruction = string.Empty;

    private string ticketIdString = string.Empty;
    //private int? FormSeriesId;
    public const int ExpeditionSeriesId = 13; // Serie de comprobante para presupuestos (talonario Q).
    private bool IsSaving;

    private async Task<IEnumerable<ELookUpItem>> SearchQuotes(string filter)
    {
        return await lookUpService.SearchApprovedQuotesAsync(filter);
    }

    private async Task OnQuoteSelected(ELookUpItem? selected)
    {
        if (selected is null || string.IsNullOrWhiteSpace(selected.Nombre))
        {
            SelectedQuote = null;
            ExtraInfo = new(); // Limpiar datos cargados
            DispatchInstruction = "";
            return;
        }

        SelectedQuote = selected;

        var quoteNumber = selected.Nombre.Split(" - ")[0];
        var quote = await expeditionService.GetQuoteByNumberAsync(quoteNumber);

        if (quote is null)
        {
            toastService.ShowError("No se pudo cargar el presupuesto.");
            return;
        }
        Model.ExternalReference = quote.Quotenumber;
        Model.RecipientName = quote.InstitutionName;
        Model.TicketId = quote.TicketId;
        ExtraInfo.Professional = quote.ProfessionalName;
        ExtraInfo.Institution = quote.InstitutionName;
        ExtraInfo.Patient = quote.PatientName;
        ExtraInfo.SurgeryDate = quote.EstimatedDate;
        DispatchInstruction = quote.Observations ?? "";
    }
    
    private string? ValidateBeforeSave()
    {
        if (Details.Count == 0)
            return "Debe incluir al menos un ítem.";
        if (Details.Any(x => x.Quantity <= 0))
            return "Hay ítems con cantidad inválida.";
        return null;
    }
    private async Task SaveAsync()
    {
        var error = ValidateBeforeSave();
        if (!string.IsNullOrEmpty(error)) { toastService.ShowError(error); return; }

        try
        {
            IsSaving = true;

            // Mapear ExtraInfoModel → ExtrainfoJson
            Model.ExtrainfoJson = JsonSerializer.Serialize(ExtraInfo);
            if (!string.IsNullOrWhiteSpace(ticketIdString) && Guid.TryParse(ticketIdString, out var tid))
                Model.TicketId = tid;   // si el header lo tiene

            var result = await expeditionService.CreateAndIssueAsync(Model, Details, ExpeditionSeriesId);

            if (result is null || !result.Success)
            {
                toastService.ShowError(result?.ErrorMessage ?? "No se pudo emitir la expedición.");
                return;
            }

            toastService.ShowSuccess($"Expedición emitida: {result.ExpeditionNumber}");
            await expeditionService.ExportPdfAsync(result.Id, result.ExpeditionNumber);
            Navigation.NavigateTo("/");
        }
        catch (Exception ex)
        {
            toastService.ShowError($"Error: {ex.Message}");
        }
        finally
        {
            IsSaving = false;
        }
    }

    private void RemoveItem(ELSExpeditionDetail item)
    {
        Details.Remove(item);
    }

    private async Task HandleValidSubmit()
    {
        // TODO: Lógica de guardado de la expedición completa
    }

    private async Task OpenStockItemSelectorModal()
    {
        var parameters = new ModalParameters();
        parameters.Add(nameof(StockItemSelectorModal.SetItems), ProductSetItems);
        parameters.Add(nameof(StockItemSelectorModal.Snapshot), BuildSnapshotFromDetails()); // ← clave

        var options = new ModalOptions { Size = ModalSize.Large, HideHeader = true };
        var modal = Modal.Show<StockItemSelectorModal>("", parameters, options);

        var result = await modal.Result;

        if (!result.Cancelled && result.Data is List<StockItemSelectionDto> selectedItems)
        {
            MergeSelectionsByBusinessKey(selectedItems);   // ← usar merge (ver abajo)
            StateHasChanged();
            toastService.ShowSuccess($"{selectedItems.Count} item(s) agregados/actualizados.");
        }
    }

    /// <summary> Fusiona la lista de ítems seleccionados en el modal con la lista principal <c>Details</c>.
    ///
    /// Reglas principales:
    /// - Se construye una clave de negocio (ProductId, LocationId, Batch, Expiration, Serial) para identificar ítems únicos.
    /// - Si el ítem ya existe en <c>Details</c>:
    ///   • Si la cantidad recibida es > 0 → se actualiza la fila existente (SET exacto, no suma).
    ///   • Si la cantidad recibida es 0 y la fila tenía cantidad previa > 0 → se interpreta como
    ///     "snapshot sin intención de borrar" y se conserva la fila (no se elimina).
    ///   • Si la cantidad recibida es 0 y no había cantidad previa → se elimina la fila.
    /// - Si el ítem no existe en <c>Details</c> y la cantidad recibida es > 0 → se agrega como nueva fila.
    /// - Si el ítem no existe y la cantidad es 0 → no se hace nada.
    /// - Si el ítem tiene número de serie → la cantidad se fuerza siempre a 1.
    ///
    /// Esta lógica evita el bug en el que, al reabrir el modal con un snapshot, los ítems volvían con
    /// cantidad = 0 y eran eliminados indebidamente de la grilla principal.
    /// </summary>
    private void MergeSelectionsByBusinessKey(List<StockItemSelectionDto> selected)
    {
        foreach (var s in selected)
        {
            var exp = s.Expiration.HasValue
                ? DateOnly.FromDateTime(s.Expiration.Value)
                : (DateOnly?)null;

            var key = StockKeys.BuildBusinessKey(
                s.ProductId,
                s.LocationId,
                s.Batch ?? string.Empty,
                exp,
                s.Serial ?? string.Empty
            );

            var existing = Details.FirstOrDefault(d =>
                StockKeys.BuildBusinessKey(d.ProductId, d.LocationId, d.Batch ?? string.Empty, d.Expiration, d.Serial ?? string.Empty) == key
            );

            // Normalización de quantity (no negativa)
            var newQty = s.Quantity < 0 ? 0 : s.Quantity;

            // Serial ⇒ siempre 1 (ignora lo que venga del modal)
            if (!string.IsNullOrWhiteSpace(s.Serial))
                newQty = 1;

            if (existing is not null)
            {
                if (newQty == 0)
                {
                    // ⚠️ Si ya había cantidad y el modal devolvió 0,
                    // lo tratamos como "snapshot sin intención de borrar" → no remover.
                    if (existing.Quantity > 0)
                        continue;

                    // 0 explícito válido (no había cantidad previa): eliminar.
                    Details.Remove(existing);
                    continue;
                }

                // SET exacto (no sumar): mantener coherencia con el modal
                existing.Quantity = newQty;

                // Actualizaciones mínimas necesarias (evitar sobreescrituras innecesarias):
                if (!string.IsNullOrWhiteSpace(s.ProductName)) existing.ProductName = s.ProductName;
                if (s.Batch is not null) existing.Batch = s.Batch;
                if (s.Serial is not null) existing.Serial = s.Serial;
                existing.Expiration = exp;
                existing.LocationId = s.LocationId;
                existing.TraceabilityType = s.TraceabilityType; // UI only
            }
            else
            {
                if (newQty > 0)
                {
                    Details.Add(new ELSExpeditionDetail
                    {
                        ProductId = s.ProductId,
                        ProductName = s.ProductName,
                        Quantity = newQty,
                        Batch = s.Batch,
                        Expiration = exp,
                        TraceabilityType = s.TraceabilityType, // UI only (no DB)
                        Serial = s.Serial,
                        LocationId = s.LocationId
                    });
                }
                // si newQty == 0 y no existía, no hacemos nada
            }
        }
    }

    private List<StockSnapshotItem> BuildSnapshotFromDetails()
    {
        return Details.Select(d =>
        {
            var key = StockKeys.BuildBusinessKey(
                d.ProductId,
                d.LocationId,
                d.Batch ?? string.Empty,
                d.Expiration,
                d.Serial ?? string.Empty
            );

            return new StockSnapshotItem
            {
                ProductId = d.ProductId,
                ProductName = d.ProductName,
                LocationId = d.LocationId,
                Batch = d.Batch ?? string.Empty,
                Expiration = d.Expiration,
                Serial = d.Serial ?? string.Empty,
                TraceabilityType = d.TraceabilityType, // UI only (no DB)
                Quantity = d.Quantity,
                BusinessKey = key
            };
        }).ToList();
    }

    private class ExtraInfoModel
    {
        public string? Professional { get; set; }
        public string? Institution { get; set; }
        public string? Patient { get; set; }
        public DateTime? SurgeryDate { get; set; }
    }
}
