using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
using Nop.Core;
using Nop.Core.Domain;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Messages;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Core.Domain.Tax;
using Nop.Core.Domain.Vendors;
using Nop.Core.Events;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
using Nop.Services.Attributes;
using Nop.Services.Blogs;
using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Events;
using Nop.Services.Helpers;
using Nop.Services.Html;
using Nop.Services.Localization;
using Nop.Services.Logging;
using Nop.Services.Messages;
using Nop.Services.News;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Services.Seo;
using Nop.Services.Shipping;
using Nop.Services.Stores;
using Nop.Services.Vendors;
using System.ComponentModel.DataAnnotations;
using System.Text;

namespace Nop.Plugin.Misc.FruitBankPlugin.Infrastructure
{
    public class FruitBankMessageTokenProvider : MessageTokenProvider
    {
        private readonly IOrderService _orderService;
        private readonly IPriceFormatter _priceFormatter;
        private readonly ICurrencyService _currencyService;
        private readonly CurrencySettings _currencySettings;
        private readonly FruitBankDbContext _dbContext;

        public FruitBankMessageTokenProvider(
            CatalogSettings catalogSettings,
            CurrencySettings currencySettings,
            IActionContextAccessor actionContextAccessor,
            IAddressService addressService,
            IAttributeFormatter<AddressAttribute, AddressAttributeValue> addressAttributeFormatter,
            IAttributeFormatter<CustomerAttribute, CustomerAttributeValue> customerAttributeFormatter,
            IAttributeFormatter<VendorAttribute, VendorAttributeValue> vendorAttributeFormatter,
            IBlogService blogService,
            ICountryService countryService,
            ICurrencyService currencyService,
            ICustomerService customerService,
            IDateTimeHelper dateTimeHelper,
            IEventPublisher eventPublisher,
            IGenericAttributeService genericAttributeService,
            IGiftCardService giftCardService,
            IHtmlFormatter htmlFormatter,
            ILanguageService languageService,
            ILocalizationService localizationService,
            ILogger logger,
            INewsService newsService,
            IOrderService orderService,
            IPaymentPluginManager paymentPluginManager,
            IPaymentService paymentService,
            IPriceFormatter priceFormatter,
            IProductService productService,
            IRewardPointService rewardPointService,
            IShipmentService shipmentService,
            IStateProvinceService stateProvinceService,
            IStoreContext storeContext,
            IStoreService storeService,
            IUrlHelperFactory urlHelperFactory,
            IUrlRecordService urlRecordService,
            IWorkContext workContext,
            MessageTemplatesSettings templatesSettings,
            PaymentSettings paymentSettings,
            StoreInformationSettings storeInformationSettings,
            TaxSettings taxSettings,
            FruitBankDbContext dbContext
        ) : base(
            catalogSettings,
            currencySettings,
            actionContextAccessor,
            addressService,
            addressAttributeFormatter,
            customerAttributeFormatter,
            vendorAttributeFormatter,
            blogService,
            countryService,
            currencyService,
            customerService,
            dateTimeHelper,
            eventPublisher,
            genericAttributeService,
            giftCardService,
            htmlFormatter,
            languageService,
            localizationService,
            logger,
            newsService,
            orderService,
            paymentPluginManager,
            paymentService,
            priceFormatter,
            productService,
            rewardPointService,
            shipmentService,
            stateProvinceService,
            storeContext,
            storeService,
            urlHelperFactory,
            urlRecordService,
            workContext,
            templatesSettings,
            paymentSettings,
            storeInformationSettings,
            taxSettings)
        {
            _orderService = orderService;
            _priceFormatter = priceFormatter;
            _currencyService = currencyService;
            _currencySettings = currencySettings;
            _dbContext = dbContext;
        }

        public override async Task AddOrderTokensAsync(
            IList<Token> tokens,
            Order order,
            int languageId,
            int vendorId = 0)
        {
            // Run base first to populate all other Order.* tokens
            await base.AddOrderTokensAsync(tokens, order, languageId, vendorId);

            // Replace the product table token with our custom version
            var existing = tokens.FirstOrDefault(t => t.Key == "Order.Product(s)");
            if (existing != null)
                tokens.Remove(existing);

            tokens.Add(new Token("Order.Product(s)", await BuildCustomProductTableAsync(order, languageId), true));
        }

        private async Task<string> BuildCustomProductTableAsync(Order order, int languageId)
        {
            var currency = await _currencyService.GetCurrencyByCodeAsync(order.CustomerCurrencyCode)
                           ?? await _currencyService.GetCurrencyByIdAsync(_currencySettings.PrimaryStoreCurrencyId);

            var items = await _orderService.GetOrderItemsAsync(order.Id);
            var itemDtos = await _dbContext.OrderItemDtos.GetAllByOrderId(order.Id).ToListAsync();

            var sb = new StringBuilder();

            sb.AppendLine(@"
<table cellspacing=""0"" cellpadding=""6"" border=""1"" style=""width:100%;border-collapse:collapse;font-family:Arial,sans-serif;font-size:13px;"">
  <thead>
    <tr style=""background-color:#4a7c3f;color:#ffffff;"">
      <th style=""text-align:left;padding:8px;"">Termék</th>
      <th style=""text-align:center;padding:8px;"">Mennyiség</th>
      <th style=""text-align:right;padding:8px;"">Egységár</th>
      <th style=""text-align:right;padding:8px;"">Összesen</th>
    </tr>
  </thead>
  <tbody>");

            var rowIndex = 0;
            foreach (var item in itemDtos)
            {
                var product = await _orderService.GetProductByOrderItemIdAsync(item.Id);
                if (product == null) continue;

                var unitPrice = await _priceFormatter.FormatPriceAsync(
                    item.UnitPriceInclTax, true, currency, languageId, true);
                var lineTotal = await _priceFormatter.FormatPriceAsync(
                    item.PriceInclTax, true, currency, languageId, true);

                var rowBg = rowIndex % 2 == 0 ? "#ffffff" : "#f2f7f0";
                rowIndex++;
                if (item.IsMeasurable)
                {
                    var averageWeight = item.AverageWeight;
                    var approximatePrice = item.Quantity * item.UnitPriceInclTax * (decimal)averageWeight;
                    sb.AppendLine($@"
                        <tr style=""background-color:{rowBg};"">
                          <td style=""padding:8px;"">{product.Name}</td>
                          <td style=""padding:8px;text-align:center;"">{item.Quantity}</td>
                          <td style=""padding:8px;text-align:right;"">{unitPrice}</td>
                          <td style=""padding:8px;text-align:right;"">Kalkuláció alatt, nagyságrendileg {approximatePrice}</td>
                        </tr>");
                }
                else
                {
                    sb.AppendLine($@"
                        <tr style=""background-color:{rowBg};"">
                          <td style=""padding:8px;"">{product.Name}</td>
                          <td style=""padding:8px;text-align:center;"">{item.Quantity}</td>
                          <td style=""padding:8px;text-align:right;"">{unitPrice}</td>
                          <td style=""padding:8px;text-align:right;"">{lineTotal}</td>
                        </tr>");
                }
            }

            var orderTotal = await _priceFormatter.FormatPriceAsync(
                order.OrderTotal, true, currency, languageId, true);

            if(itemDtos.Any(i => i.IsMeasurable))
            {
                sb.AppendLine($@"
                    <tr style=""background-color:#e8f0e5;font-weight:bold;"">
                      <td colspan=""3"" style=""padding:8px;text-align:right;"">Végösszeg:</td>
                      <td style=""padding:8px;text-align:right;"">Mérendő termék miatt kalkuláció alatt...</td>
                    </tr>");
            }

            else
            {
                sb.AppendLine($@"
                    <tr style=""background-color:#e8f0e5;font-weight:bold;"">
                      <td colspan=""3"" style=""padding:8px;text-align:right;"">Végösszeg:</td>
                      <td style=""padding:8px;text-align:right;"">{orderTotal}</td>
                    </tr>");

            }


            sb.AppendLine("  </tbody>\n</table>");

            return sb.ToString();
        }
    }
}