using FruitBank.Common.Enums;
using FruitBank.Common.Interfaces;
using FruitBank.Common.Server;
using Mango.Nop.Core.Dtos;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Messages;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Tax;
using Nop.Core.Events;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
using Nop.Plugin.Misc.FruitBankPlugin.Models;
using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders;
using Nop.Services.Attributes;
using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Events;
using Nop.Services.Localization;
using Nop.Services.Messages;
using Nop.Services.Orders;
using Nop.Services.Plugins;
using Nop.Web.Framework.Events;
using Nop.Web.Framework.Menu;
using Nop.Web.Models.Sitemap;
using NUglify.JavaScript.Syntax;
using System.Linq;
using System.Xml.Linq;

namespace Nop.Plugin.Misc.FruitBankPlugin.Services
{
    public class EventConsumer : BaseAdminMenuCreatedEventConsumer, IConsumer<EntityUpdatedEvent<Customer>>, IConsumer<EntityInsertedEvent<Customer>>, IConsumer<OrderPlacedEvent>, IConsumer<EntityUpdatedEvent<Order>>, IConsumer<AdminMenuCreatedEvent>
    {
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly IProductService _productService;
        private readonly ISpecificationAttributeService _specificationAttributeService;
        private readonly IOrderService _orderService;
        private readonly IProductAttributeService _productAttributeService;
        private readonly IWorkContext _workContext;
        private readonly IStoreContext _storeContext;
        private readonly IAdminMenu _adminMenu;
        private readonly ILocalizationService _localizationService;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IAddressService _addressService;
        private readonly FruitBankAttributeService _fruitBankAttributeService;
        private readonly FruitBankDbContext _dbContext;
        private readonly IAttributeParser<CustomerAttribute, CustomerAttributeValue> _attributeParser;
        private readonly ICustomerService _customerService;
        private readonly IWorkflowMessageService _workflowMessageService;
        private readonly FruitBankNotificationService _fruitBankNotificationService;

        public EventConsumer(
            IGenericAttributeService genericAttributeService,
            IProductService productService,
            ISpecificationAttributeService specificationAttributeService,
            IOrderService orderService,
            IProductAttributeService productAttributeService,
            IPluginManager<IPlugin> pluginManager,
            IWorkContext workContext,
            IStoreContext storeContext,
            IAdminMenu adminMenu,
            ILocalizationService localizationService,
            IHttpContextAccessor httpContextAccessor,
            IAddressService addressService,
            FruitBankAttributeService fruitBankAttributeService,
            FruitBankDbContext dbContext,
            IAttributeParser<CustomerAttribute, CustomerAttributeValue> attributeParser,
            ICustomerService customerService,
            IWorkflowMessageService workflowMessageService,
            FruitBankNotificationService fruitBankNotificationService
            ) : base(pluginManager)
        {
            _genericAttributeService = genericAttributeService;
            _productService = productService;
            _specificationAttributeService = specificationAttributeService;
            _orderService = orderService;
            _productAttributeService = productAttributeService;
            _workContext = workContext;
            _storeContext = storeContext;
            _adminMenu = adminMenu;
            _localizationService = localizationService;
            _httpContextAccessor = httpContextAccessor;
            _addressService = addressService;
            _fruitBankAttributeService = fruitBankAttributeService;
            _dbContext = dbContext;
            _attributeParser = attributeParser;
            _customerService = customerService;
            _workflowMessageService = workflowMessageService;
            _fruitBankNotificationService = fruitBankNotificationService;
        }

        protected override string PluginSystemName => "Misc.FruitBankPlugin";

        public async Task HandleEventAsync(OrderPlacedEvent eventMessage)
        {
            var order = eventMessage?.Order;
            if (order == null) return;

            // Transfer the customer's chosen delivery datetime to the order as DateOfReceipt
            var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId);
            if (customer == null) return;

            var storeId = order.StoreId;
            const string pendingKey = "QuickOrderPendingDeliveryDateTime";

            var pendingDateTime = await _fruitBankAttributeService
                .GetGenericAttributeValueAsync<Nop.Core.Domain.Customers.Customer, DateTime?>(order.CustomerId, pendingKey, storeId);

            if (pendingDateTime.HasValue)
            {
                await _fruitBankAttributeService
                    .InsertOrUpdateGenericAttributeAsync<Nop.Core.Domain.Orders.Order, DateTime>(
                        order.Id, nameof(IOrderDto.DateOfReceipt), pendingDateTime.Value, storeId);

                // Clean up — the value has been transferred to the order
                await _fruitBankAttributeService
                    .DeleteGenericAttributeAsync<Nop.Core.Domain.Customers.Customer>(order.CustomerId, pendingKey, storeId);

                Console.WriteLine($"[EventConsumer] OrderPlaced #{order.Id} – DateOfReceipt set to {pendingDateTime.Value:u}");
            }
        }

        public async Task HandleEventAsync(EntityUpdatedEvent<Order> eventMessage)
        {
            await SaveOrderCustomAttributesAsync(eventMessage.Entity);
            if (eventMessage.Entity == null) return;

            var orderDto = await _dbContext.OrderDtos.GetByIdAsync(eventMessage.Entity.Id, true);
            if (orderDto == null) return;

            if (orderDto.MeasuringStatus == MeasuringStatus.Audited)
            {
                var alreadySent = await _fruitBankAttributeService
                    .GetGenericAttributeValueAsync<Order, bool>(eventMessage.Entity.Id, "OrderAuditedNotificationSent");

                if (!alreadySent)
                {
                    await _fruitBankNotificationService
                        .SendOrderAuditedCustomerNotificationAsync(eventMessage.Entity, orderDto.IsMeasurable);

                    await _fruitBankAttributeService
                        .InsertOrUpdateGenericAttributeAsync<Order, bool>(
                            eventMessage.Entity.Id, "OrderAuditedNotificationSent", true);
                }
            }
            else if (orderDto.MeasuringStatus == MeasuringStatus.Started)
            {
                var alreadySent = await _fruitBankAttributeService
                    .GetGenericAttributeValueAsync<Order, bool>(eventMessage.Entity.Id, "OrderStartedNotificationSent");

                if (!alreadySent)
                {
                    await _fruitBankNotificationService
                        .SendOrderStartedCustomerNotificationAsync(eventMessage.Entity, orderDto.IsMeasurable);

                    await _fruitBankAttributeService
                        .InsertOrUpdateGenericAttributeAsync<Order, bool>(
                            eventMessage.Entity.Id, "OrderStartedNotificationSent", true);
                }
            }

            
        }


        private async Task SaveOrderCustomAttributesAsync(Order order)
        {
            if (order == null) return;

            var hasForm = _httpContextAccessor.HttpContext?.Request?.HasFormContentType ?? false;
            var form = hasForm ? _httpContextAccessor.HttpContext.Request.Form : null;

            if (form == null || form.Count == 0) return;

            //if (form.ContainsKey(nameof(IMeasurable.IsMeasurable)))
            //{
            //    var isMeasurable = form[nameof(IMeasurable.IsMeasurable)].ToString().Contains("true");
            //    //var isMeasurable = CommonHelper.To<bool>(form[nameof(IMeasurable.IsMeasurable)].ToString());

            //    await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Order, bool>(order.Id, nameof(IMeasurable.IsMeasurable), isMeasurable);
            //}

            if (form.ContainsKey(nameof(IOrderDto.DateOfReceipt)))
            {
                var dateOfReceiptString = form[nameof(IOrderDto.DateOfReceipt)];
                if (string.IsNullOrWhiteSpace(dateOfReceiptString)) return;

                if (DateTime.TryParse(dateOfReceiptString, out var dateOfReceipt))
                    await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Order, DateTime>(order.Id, nameof(IOrderDto.DateOfReceipt), dateOfReceipt);
            }
        }

        public override async Task HandleEventAsync(AdminMenuCreatedEvent eventMessage)
        {
            var rootNode = eventMessage.RootMenuItem;
                      

            var shippingsListMenuItem = new AdminMenuItem
            {
                Visible = true,
                OpenUrlInNewTab = true,
                SystemName = "FruitBank",
                Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.ShippingsList"), // You can localize this with await _localizationService.GetResourceAsync("...")
                IconClass = "fas fa-shipping-fast",
                //Url = _adminMenu.GetMenuItemUrl("Shipping", "List")
                Url = "https://app.fruitbank.hu"
            };


            //var createShippingMenuItem = new AdminMenuItem
            //{
            //    Visible = true,
            //    SystemName = "Shippings.Create",
            //    Title = "Create Shipping",
            //    IconClass = "far fa-circle",
            //    Url = _adminMenu.GetMenuItemUrl("Shipping", "Create")
            //};

            //var editShippingMenuItem = new AdminMenuItem
            //{
            //    Visible = true,
            //    SystemName = "Shippings.Edit",
            //    Title = "Edit Shipping",
            //    IconClass = "far fa-circle",
            //    Url = _adminMenu.GetMenuItemUrl("Shipping", "Edit")
            //};

            // Create a new top-level menu item
            var shippingsMenuItem = new AdminMenuItem
            {
                Visible = true,
                SystemName = "FruitBank",
                Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Shippings"), // You can localize this with await _localizationService.GetResourceAsync("...")
                IconClass = "fas fa-shipping-fast",
                //Url = _adminMenu.GetMenuItemUrl("Shipping", "List")
                //ChildNodes = [shippingsListMenuItem, createShippingMenuItem, editShippingMenuItem]
                ChildNodes = [shippingsListMenuItem]
            };

            var shippingConfigurationItem = rootNode;
            shippingConfigurationItem.ChildNodes.Insert(2, shippingsMenuItem);

            // Create a new top-level menu item
            var voiceOrderMenuItem = new AdminMenuItem
            {
                Visible = true,
                SystemName = "FruitBank",
                Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.VoiceOrder"),
                IconClass = "fas fa-microphone",
                Url = _adminMenu.GetMenuItemUrl("VoiceOrder", "Create")
            };

            shippingConfigurationItem.ChildNodes.Insert(3, voiceOrderMenuItem);

            var preorderAvailabilityMenuItem = new AdminMenuItem
            {
                Visible = true,
                SystemName = "PreOrderAvailability",
                Title = "Előrendelés — elérhetőség",
                IconClass = "fas fa-calendar-check",
                Url = _adminMenu.GetMenuItemUrl("PreOrderAvailability", "Index")
            };

            //shippingConfigurationItem.ChildNodes.Insert(4, preorderAvailabilityMenuItem);

            var preorderListMenuItem = new AdminMenuItem
            {
                Visible = true,
                SystemName = "PreOrders.List",
                Title = "Előrendelések",
                IconClass = "fas fa-calendar-plus",
                Url = _adminMenu.GetMenuItemUrl("PreOrderAdmin", "List")
            };

            var preordersRootMenuItem = new AdminMenuItem
            {
                Visible = true,
                SystemName = "FruitBank",
                Title = "Előrendelés",
                //Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.PreOrders"), // You can localize this with await _localizationService.GetResourceAsync("...")
                IconClass = "fas fa-heart",
                //Url = _adminMenu.GetMenuItemUrl("Shipping", "List")
                //ChildNodes = [shippingsListMenuItem, createShippingMenuItem, editShippingMenuItem]
                ChildNodes = [preorderAvailabilityMenuItem, preorderListMenuItem]
            };

            rootNode.ChildNodes.Insert(3, preordersRootMenuItem);

            //shippingConfigurationItem.ChildNodes.Insert(5, preorderListMenuItem);


            // Create a new top-level menu item
            var InvoiceSyncMenuItem = new AdminMenuItem
            {
                Visible = true,
                SystemName = "FruitBank",
                Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.InnVoiceOrderSync"), // You can localize this with await _localizationService.GetResourceAsync("...")
                IconClass = "fas fa-file-invoice",
                Url = _adminMenu.GetMenuItemUrl("InnVoiceOrderSync", "Index")
                //ChildNodes = [shippingsListMenuItem, createShippingMenuItem, editShippingMenuItem]

            };


            shippingConfigurationItem.ChildNodes.Insert(4, InvoiceSyncMenuItem);

            // Create a new top-level menu item
            var AppDownloadMenuItem = new AdminMenuItem
            {
                Visible = true,
                SystemName = "FruitBank",
                Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.AppDownload"), // You can localize this with await _localizationService.GetResourceAsync("...")
                IconClass = "fas fa-mobile",
                Url = _adminMenu.GetMenuItemUrl("AppDownload", "Index")
                //ChildNodes = [shippingsListMenuItem, createShippingMenuItem, editShippingMenuItem]
            };


            shippingConfigurationItem.ChildNodes.Insert(4, AppDownloadMenuItem);

            var invoiceListMenuItem = new AdminMenuItem
            {
                Visible = true,
                SystemName = "FruitBank",
                Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.InvoicesList"), // You can localize this with await _localizationService.GetResourceAsync("...")
                IconClass = "fas fa-file-invoice",
                Url = _adminMenu.GetMenuItemUrl("Invoices", "List")
            };

            // Create a new top-level menu item
            var invoicesMenuItem = new AdminMenuItem
            {
                Visible = true,
                SystemName = "FruitBank",
                Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Invoices"), // You can localize this with await _localizationService.GetResourceAsync("...")
                IconClass = "fas fa-file-invoice",
                //Url = _adminMenu.GetMenuItemUrl("Shipping", "List")
                ChildNodes = [invoiceListMenuItem]
            };

            var invoiceConfigurationItem = rootNode;
            invoiceConfigurationItem.ChildNodes.Insert(2, invoicesMenuItem);


            var configurationItem = rootNode.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Configuration"));
            if (configurationItem is null)
                return;

            var shippingItem = configurationItem.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Shipping"));
            var widgetsItem = configurationItem.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Widgets"));
            if (shippingItem is null && widgetsItem is null)
                return;

            var index = shippingItem is not null ? configurationItem.ChildNodes.IndexOf(shippingItem) : -1;
            if (index < 0)
                index = widgetsItem is not null ? configurationItem.ChildNodes.IndexOf(widgetsItem) : -1;
            if (index < 0)
                return;

            configurationItem.ChildNodes.Insert(index + 1, new AdminMenuItem
            {

                Visible = true,
                SystemName = "FruitBank",
                Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.AI"),
                IconClass = "far fa-dot-circle",
                ChildNodes = new List<AdminMenuItem>
                {
                    new()
                    {

                        Visible = true,
                        SystemName = "FruitBank",
                        Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Configure"),
                        IconClass = "far fa-circle",
                        Url = _adminMenu.GetMenuItemUrl("FruitBankPlugin", "Configure"),

                    }
                }
            });

        }

        public async Task HandleEventAsync(EntityInsertedEvent<Customer> eventMessage)
        {
            await ProcessCustomerEventAsync(eventMessage?.Entity);
        }

        public async Task HandleEventAsync(EntityUpdatedEvent<Customer> eventMessage)
        {
            await ProcessCustomerEventAsync(eventMessage?.Entity);
        }

        private async Task ProcessCustomerEventAsync(Customer customer)
        {
            if (customer == null)
            {
                return;
            }

            if (!IsRegisteredCustomer(customer))
            {
                return;
            }

            await EnsureBillingAddressAsync(customer);
            await SynchronizeTaxInformationAsync(customer);
        }

        private bool IsRegisteredCustomer(Customer customer)
        {
            var customerRoles = _dbContext.GetCustomerRolesByCustomerId(customer.Id);
            return customerRoles?.Any(role => role.SystemName == "Registered") ?? false;
        }

        private async Task EnsureBillingAddressAsync(Customer customer)
        {
            if (customer.BillingAddressId != null)
            {
                return;
            }

            var address = new Address
            {
                ZipPostalCode = customer.ZipPostalCode,
                City = customer.City,
                Address1 = customer.StreetAddress,
                Address2 = customer.StreetAddress2,
                CountryId = customer.CountryId > 0 ? customer.CountryId : null,
                StateProvinceId = customer.StateProvinceId > 0 ? customer.StateProvinceId : null,
                PhoneNumber = customer.Phone,
                Company = customer.Company,
                FirstName = customer.FirstName,
                LastName = customer.LastName,
                Email = customer.Email,
                County = customer.County
            };

            await _addressService.InsertAddressAsync(address);
            await _dbContext.AddCustomerAddressMappingAsync(customer.Id, address.Id);
            customer.BillingAddressId = address.Id;
        }

        private async Task SynchronizeTaxInformationAsync(Customer customer)
        {
            string attributesXml = customer.CustomCustomerAttributesXML;

            string taxId = null;

            if (!string.IsNullOrWhiteSpace(attributesXml))
            {
                var doc = XDocument.Parse(attributesXml);
                taxId = doc.Descendants("CustomerAttribute")
                           .FirstOrDefault(el => (int?)el.Attribute("ID") == 1) // your TaxId attribute ID
                           ?.Descendants("Value")
                           .FirstOrDefault()
                           ?.Value;
            }

            if (!string.IsNullOrWhiteSpace(taxId) && string.IsNullOrWhiteSpace(customer.VatNumber))
            {
                customer.VatNumber = taxId;
            }
            else if (string.IsNullOrWhiteSpace(taxId) && !string.IsNullOrWhiteSpace(customer.VatNumber))
            {
                await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Customer, string>(
                    customer.Id,
                    "TaxId",
                    customer.VatNumber);
            }

            _dbContext.Customers.Update(customer, false);
        }
    }
}
