using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using WK5.Core;
using WK5.Core.Basis.Erweiterungen;
using WK5.Core.Drucken;
using WK5.Core.Models;
using WK5.Core.Models.Inventuren;
using WK5.Core.PageModels.Inventuren;
using WK5_Blazor.Authorization;

namespace WK5_Blazor.Pages.Inventur
{
    public partial class LagerplatzScannen
    {
        [Parameter] public int InventurId { get; set; }
        [Parameter] public string Basislager { get; set; } = String.Empty;
        [Parameter] public string Lagerplatz { get; set; } = String.Empty;



#nullable disable
        [CascadingParameter] public AppMitarbeiter Mitarbeiter { get; set; }
#nullable enable
        public InventurBuchungInput Input { get; set; } = new InventurBuchungInput();

        private InventurArtikel[] _lagerplatzArtikel = Array.Empty<InventurArtikel>();

        private InventurArtikelGebucht[] _lagerplatzArtikelGebucht = Array.Empty<InventurArtikelGebucht>();


        private bool _initialized;
        private bool _gesperrt;
        private decimal _menge = 1;
        private bool _showAndererLagerortModal;
        private ValidationContext? validationContext;
        #region Modals
        private bool _showArtikelnummerSuchenModal;
        private bool _showVpeModal;
        private bool _showAbschließenModal;
        private bool _showKorrekturBuchenModal;
        private bool _showSeriennummerModal;
        private bool _showRegalFinderModal;
        private InventurArtikelGebucht? KorrekturInput { get; set; }
        private Artikel? _selectedSuchArtikel;
        private List<Seriennummer> _seriennummern = new List<Seriennummer>();

        private IArtikel? _selectedRegalArtikel;


        #endregion

        private readonly List<(string artikelnummer, string lagerort)> _andererLagerort = new List<(string, string)>();
        private InventurBuchungsAnfrage? _request;
        private InventurBuchungsResponse? _lastResponse;

        private InventurArtikelGebucht? _letzteBuchungArtikel;

        private async Task EtikettDrucken(string artikelnummer)
        {
            PrintEtikett.Print(artikelnummer);
            await jsRuntime.ShowToast(ToastType.success, "Etikett erfolgreich gedruckt");
        }
        private async Task RegalAbschließen()
        {
            _andererLagerort.Clear();
            await inventurService.RegalAbschließenAsync(InventurId, Basislager, Lagerplatz);

            foreach (var artikel in _lagerplatzArtikelGebucht)
            {
                var response = await inventurService.SetLagerplatzDurchInventur(artikel, Lagerplatz);
                if (!response.Success)
                {
                    _andererLagerort.Add((artikel.Artikelnummer, response.Value as string ?? String.Empty));
                }
            }

            _showAndererLagerortModal = _andererLagerort.Any();

            _gesperrt = true;
        }

        private async Task RegalÖffnen()
        {
            await inventurService.RegalÖffnenAsync(InventurId, Basislager, Lagerplatz);
            _gesperrt = false;
        }
        private async Task Buchen(decimal menge, bool ignoreVpe = false)
        {
            if (_gesperrt)
            {
                return;
            }

            if (menge <= 0)
            {
                await jsRuntime.InvokeVoidAsync("showToast", "error", "Buchung kann nicht für eine Menge <= 0 durchgeführt werden", 1500);
                return;
            }

            _request = new InventurBuchungsAnfrage(
                UserId: Mitarbeiter.PersonalNummer,
                InventurId: InventurId,
                Regal: Lagerplatz,
                Artikelnummer: Input.Artikelnummer,
                Menge: menge,
                Seriennummer: Input.Seriennummer,
                Kommentar: Input.Kommentar,
                IgnoreVpe: ignoreVpe
            );

            _lastResponse = await inventurService.BuchenAsync(_request);

            if (_lastResponse.Success)
            {

                await jsRuntime.InvokeVoidAsync("showToast", "success", _lastResponse.Message ?? String.Empty, 1500);
                _lagerplatzArtikelGebucht = await inventurService.GetGebuchteArtikelByUnterlagerAsync(InventurId, Lagerplatz).ToArrayAsync();
                // Es kann sein, dass wir eine Seriennummer, oder eine EAN eingescannt haben, dann finden wir den Artikel natürlich nicht nach der Artikelnummer
                // Die API liefert aber die korrigierte Anfrage zurück, sodass wir von dieser die Artikelnummer entnehmen können.
                var anfrageMitKorrekterArtikelnummer = _lastResponse.Value as InventurBuchungsAnfrage;
                if (anfrageMitKorrekterArtikelnummer is not null)
                {
                    _letzteBuchungArtikel = _lagerplatzArtikelGebucht.Where(x => x.Artikelnummer.Equals(anfrageMitKorrekterArtikelnummer.Artikelnummer)).FirstOrDefault();
                }
            }
            else
            {
                switch (_lastResponse.Status)
                {

                    case InventurBuchungStatus.SeriennummerBenötigt:
                        _seriennummern = _lastResponse.Value as List<Seriennummer> ?? new List<Seriennummer>();
                        _showSeriennummerModal = true;
                        await jsRuntime.InvokeVoidAsync("showToast", "error", _lastResponse.Message ?? String.Empty, 1500);
                        break;
                    case InventurBuchungStatus.VpeVorschlagen:
                        _showVpeModal = true;
                        break;
                    default:
                        await jsRuntime.InvokeVoidAsync("showToast", "error", _lastResponse.Message ?? String.Empty, 1500);
                        break;
                }
            }

            Input.Artikelnummer = String.Empty;
            _menge = 1;
            Input.Kommentar = String.Empty;
            Input.Seriennummer = String.Empty;
        }

        private async Task ManuellBuchen(decimal menge)
        {
            if (_selectedSuchArtikel is not null)
            {
                Input.Artikelnummer = _selectedSuchArtikel.Artikelnummer;
                await Buchen(menge, true);
                _selectedSuchArtikel = null;
                _showArtikelnummerSuchenModal = false;
            }
        }
        private async Task VpeConfirmedAsync()
        {
            if (_lastResponse is not null && _lastResponse.Value is not null && _request is not null)
            {
                Input.Artikelnummer = _request.Artikelnummer;
                await Buchen((int)_lastResponse.Value, true);
                _showVpeModal = false;
            }
        }
        protected override async Task OnParametersSetAsync()
        {
            _lagerplatzArtikel = await inventurService.GetArtikelByUnterlagerAsync(Lagerplatz).ToArrayAsync();
            _lagerplatzArtikelGebucht = await inventurService.GetGebuchteArtikelByUnterlagerAsync(InventurId, Lagerplatz).ToArrayAsync();
            _gesperrt = await inventurService.IstRegalAbgeschlossenAsync(InventurId, Basislager, Lagerplatz);
            _initialized = true;
        }

        private bool IstArtikelInLagerplatz(string artikelnummer)
        {
            return _lagerplatzArtikel.Where(x => x.Artikelnummer.Equals(artikelnummer, StringComparison.OrdinalIgnoreCase)).FirstOrDefault() is not null;
        }

        private void ShowBuchenModal(InventurArtikelGebucht artikel)
        {

            KorrekturInput = artikel;

            validationContext = new ValidationContext(KorrekturInput);
            _showKorrekturBuchenModal = true;
        }

        private async Task KorrekturBuchen()
        {
            if (KorrekturInput is not null)
            {
                var result = await inventurService.UpdateBuchung(KorrekturInput, Mitarbeiter.PersonalNummer);
                await jsRuntime.ShowToast(result.Success ? ToastType.success : ToastType.error, result.Message ?? String.Empty);
                _lagerplatzArtikelGebucht = await inventurService.GetGebuchteArtikelByUnterlagerAsync(InventurId, Lagerplatz).ToArrayAsync();
                _letzteBuchungArtikel = _lagerplatzArtikelGebucht.Where(x => x.Artikelnummer.Equals(KorrekturInput.Artikelnummer)).FirstOrDefault();
            }
        }
   
        private async Task CloseVpeModalAsync()
        {
            _showVpeModal = false;
            await jsRuntime.FocusByIdAsync("artikelnummer-eingabe");
        }
    }
}
