using AyCode.Core.Extensions;
using AyCode.Core.Loggers;
using DevExpress.Blazor;
using FruitBank.Common.Dtos;
using FruitBank.Common.Entities;
using FruitBank.Common.Enums;
using FruitBank.Common.Helpers;
using FruitBank.Common.Interfaces;
using FruitBank.Common.Models;
using FruitBankHybrid.Shared.Models;
using FruitBankHybrid.Shared.Services;
using FruitBankHybrid.Shared.Services.Loggers;
using FruitBankHybrid.Shared.Services.SignalRs;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using ILogger = Mango.Nop.Core.Loggers.ILogger;

namespace FruitBankHybrid.Shared.Pages
{
    public partial class MeasuringIn : ComponentBase
    {
        [Inject] public required IEnumerable<IAcLogWriterClientBase> LogWriters { get; set; }
        [Inject] public required FruitBankSignalRClient FruitBankSignalRClient { get; set; }
        [Inject] public required NavigationManager NavManager{ get; set; }
        [Inject] public required LoggedInModel LoggedInModel { get; set; }

        private ILogger _logger = null!;
        private string _errorText;

        private enum MeasuringTab
        {
            DailyTasks = 0,
            Measuring = 1
        }

        private MeasuringTab _activeTab = MeasuringTab.DailyTasks;
        private IEnumerable<MeasuringStatus> _statusFilter = [];

        private List<Shipping> NotMeasuredShippings { get; set; } = null!;
        private Shipping? SelectedShipping { get; set; }
        //private ShippingDocument? SelectedShippingDocument { get; set; }
        private ShippingItem? SelectedShippingItem { get; set; }

        public bool LoadingPanelVisible { get; set; } = true;
        protected bool BtnSaveEnabled { get; set; }

        private List<ShippingItem>? _shippingItemsDataSource;
        private List<MeasuringDateSelectorModel> _measuringDates = null!;

        private IReadOnlyList<Shipping> FilteredShippings => NotMeasuredShippings is null
            ? []
            : _statusFilter.Any()
                ? NotMeasuredShippings.Where(s => _statusFilter.Contains(MeasurementService.GetShippingMeasuringStatus(s))).ToList()
                : NotMeasuredShippings;

        protected override async Task OnInitializedAsync()
        {
            LoadingPanelVisible = true;

            _logger = new LoggerClient<MeasuringIn>(LogWriters.ToArray());
            _logger.Info("OnInitializedAsync");

            await RefreshShippingsFromDb(DateTime.Now);
            await base.OnInitializedAsync();
        }

        private async Task RefreshShippingsFromDb(DateTime dateTime)
        {
            var shippings = await FruitBankSignalRClient.GetNotMeasuredShippings() ?? [];

            _measuringDates = shippings.Select(shipping => new MeasuringDateSelectorModel(shipping.Id, shipping.ShippingDate.Date, shipping.IsAllMeasured)).ToList();
            NotMeasuredShippings = shippings.Where(shipping => MeasurementService.DaysEqual(shipping.ShippingDate.Date, dateTime)).ToList();

            SelectedShipping = NotMeasuredShippings.FirstOrDefault();
            //if (SelectedShipping != null && SelectedShippingItem != null && (SelectedShippingItem.ShippingDocument?.ShippingId ?? 0) == SelectedShipping.Id)
            //{
            //    SelectedShippingItem = _shippingItemsDataSource.
            //}

            LoadingPanelVisible = false;
        }

        private static List<ShippingItem>? GetShippingItemsDataSource(Shipping? shipping)
            => shipping?.ShippingDocuments?.SelectMany(sd => sd.ShippingItems!).OrderBy(si => si.ProductName).ToList() ?? null;
        
        private async Task OnMeasuringDateChanged(DateTime selectedDateTime)
            => await RefreshShippingsFromDb(selectedDateTime);


        private void OnCustomDisabledMeasuringDate(CalendarCustomDisabledDateEventArgs args)
            => MeasurementService.OnCustomDisabledDate(args, _measuringDates);

        private string GetMeasuringDateCssClassNames(DateTime date)
            => MeasurementService.GetShippingDateCssClassNames(date, _measuringDates);

        private string GetShippingPalletsCssClassNames(string fieldName, ShippingItemPallet shippingItemPallet)
            => MeasurementService.GetCustomItemPalletsCssClassNames(fieldName, shippingItemPallet, SelectedShippingItem!.IsMeasurable);
        
        private void OnSelectedShippingChanged(SelectedDataItemChangedEventArgs<Shipping> eventArgs)
        {
            var shipping = eventArgs.DataItem;

            PrepareShippingItems(shipping);

            _shippingItemsDataSource = GetShippingItemsDataSource(shipping);
            SelectedShippingItem = _shippingItemsDataSource?.FirstOrDefault();
        }

        private void OnSelectedShippingItemChanged(SelectedDataItemChangedEventArgs<ShippingItem> eventArgs)
        {
            BtnSaveEnabled = false;
            var shippingItem = eventArgs.DataItem;

            if (shippingItem == null)
            {
                SelectedShippingItem = null;
                return;
            }

            //SelectedShippingDocument!.IsAllMeasured = SelectedShippingDocument.ShippingItems?.All(si => si.IsMeasured) ?? false;
            shippingItem.ShippingDocument!.IsAllMeasured = shippingItem.ShippingDocument.ShippingItems?.All(si => si.IsMeasured) ?? false;
            SelectedShipping!.IsAllMeasured = SelectedShipping.ShippingDocuments?.All(sd => sd.IsAllMeasured) ?? false;

            var shippingDate = _measuringDates.FirstOrDefault(shipping => shipping.ShippingId == SelectedShipping.Id);
            if (shippingDate != null) shippingDate.IsMeasured = SelectedShipping.IsAllMeasured;

            //PrepareShippingItems(SelectedShipping);
        }

        private async Task RefreshSelectedShippingItemMeasuredValuesFromDb(int shippingItemId)
        {
            RefreshSelectedShippingItemMeasuredValuesFromDb(await FruitBankSignalRClient.GetShippingItemById(shippingItemId));
        }

        private void RefreshSelectedShippingItemMeasuredValuesFromDb(ShippingItem? shippingItemFromDb)
        {
            if (SelectedShipping == null || SelectedShippingItem?.ShippingDocument == null || shippingItemFromDb == null) return;

            //SelectedShippingItem.MeasuredQuantity = shippingItemFromDb.MeasuredQuantity;
            //SelectedShippingItem.MeasuredNetWeight = shippingItemFromDb.MeasuredNetWeight;
            //SelectedShippingItem.MeasuredGrossWeight = shippingItemFromDb.MeasuredGrossWeight;
            //SelectedShippingItem.IsMeasurable = shippingItemFromDb.IsMeasurable;
            //SelectedShippingItem.IsMeasured = shippingItemFromDb.IsMeasured;

            SelectedShippingItem.ShippingDocument.ShippingItems?.UpdateCollection(shippingItemFromDb, false);
            _shippingItemsDataSource?.UpdateCollection(shippingItemFromDb, false);

            SelectedShippingItem = shippingItemFromDb;

            StateHasChanged();
        }
        private async Task OnOrdersRefreshClick()
        {
            LoadingPanelVisible = true;

            await RefreshShippingsFromDb(SelectedShipping?.ShippingDate ?? DateTime.Now);
            StateHasChanged();
        }

        private Task OnShippingItemPalletValueChanged(ShippingItemPallet shippingItemPallet, ShippingItem shippingItem)
        {
            MeasuringValuesHelper.SetShippingItemTotalMeasuringValues(shippingItem);
            BtnSaveEnabled = shippingItem.IsValidMeasuringValues() && shippingItemPallet.IsValidMeasuringValues(shippingItem.IsMeasurable);

            StateHasChanged();
            return Task.CompletedTask;
        }

        private async Task OnShippingItemPalletSaved(ShippingItemPallet? responseShippingItemPallet)
        {
            if (responseShippingItemPallet != null)
            {
                responseShippingItemPallet.ShippingItem = SelectedShippingItem;

                SelectedShippingItem!.ShippingItemPallets!.UpdateCollection(responseShippingItemPallet, false);
                SelectedShippingItem.IsMeasured = SelectedShippingItem!.ShippingItemPallets!.All(sip => sip.IsMeasuredAndValid(SelectedShippingItem.IsMeasurable));

                MeasuringValuesHelper.SetShippingItemTotalMeasuringValues(SelectedShippingItem);
            }
            else DisplayErrorText($"Sikertelen volt a raklap adatainak mentése!");

            await InvokeAsync(StateHasChanged);
        }
        
        private bool IsShippingitemPalletMeasuredAndValid(ShippingItemPallet shippingItemPallet)
            => MeasurementService.IsCustomItemPalletMeasuredAndValid(shippingItemPallet, SelectedShippingItem!.IsMeasurable);

        private void LogErrorAndDisplayText(string errorText, Exception? ex = null)
        {
            _logger.Error($"{errorText}", ex);
            DisplayErrorText(errorText);
        }

        private void DisplayErrorText(string errorText)
        {
            _errorText = errorText;
            //Nem végezhető el a mérés, nincs megadva a ProductId! Jelezze a vezetőségnek...
        }

        /// <summary>
        /// Navigates from a card click (Napi feladatok tab) to the Mérés tab with the selected shipping.
        /// </summary>
        private void NavigateToMeasuringTab(Shipping shipping)
        {
            SelectedShipping = shipping;

            PrepareShippingItems(shipping);
            _shippingItemsDataSource = GetShippingItemsDataSource(shipping);
            SelectedShippingItem = _shippingItemsDataSource?.FirstOrDefault();

            _activeTab = MeasuringTab.Measuring;
        }

        private void PrepareShippingItems(Shipping? shipping)
        {
            if (shipping?.ShippingDocuments == null) return;

            foreach (var shippingShippingDocument in shipping.ShippingDocuments)
            {
                shippingShippingDocument.Shipping = shipping;
                if (shippingShippingDocument.ShippingItems == null) continue;

                foreach (var shippingItem in shippingShippingDocument.ShippingItems)
                {
                    shippingItem.ShippingDocument = shippingShippingDocument;
                    MeasuringValuesHelper.SetShippingItemTotalMeasuringValues(shippingItem);

                    shippingItem.ShippingItemPallets ??= new List<ShippingItemPallet>(shippingItem.MeasuringCount);

                    for (var i = 0; i < shippingItem.MeasuringCount; i++)
                    {
                        if (i < shippingItem.ShippingItemPallets.Count)
                        {
                            shippingItem.ShippingItemPallets[i].ShippingItem = shippingItem;
                            continue;
                        }

                        shippingItem.ShippingItemPallets.Add(MeasurementService.CreateNewShippingItemPallet(shippingItem, LoggedInModel.CustomerDto));
                    }
                }
            }
        }
    }
}
