using Grand.Business.Core.Interfaces.Catalog.Categories;
using Grand.Business.Core.Interfaces.Catalog.Collections;
using Grand.Business.Core.Interfaces.Catalog.Products;
using Grand.Business.Core.Interfaces.Checkout.Orders;
using Grand.Business.Core.Interfaces.Checkout.Shipping;
using Grand.Business.Core.Interfaces.Common.Localization;
using Grand.Business.Core.Interfaces.Customers;
using Grand.Business.Core.Interfaces.Marketing.Documents;
using Grand.Business.Core.Interfaces.Storage;
using Grand.Domain.Common;
using Grand.Domain.Documents;
using Grand.Domain.Payments;
using Grand.Web.Admin.Extensions.Mapping;
using Grand.Web.Admin.Interfaces;
using Grand.Web.Admin.Models.Documents;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace Grand.Web.Admin.Services;

public class DocumentViewModelService : IDocumentViewModelService
{
    private readonly ICategoryService _categoryService;
    private readonly ICollectionService _collectionService;
    private readonly ICustomerService _customerService;
    private readonly IDocumentService _documentService;
    private readonly IDocumentTypeService _documentTypeService;
    private readonly IDownloadService _downloadService;
    private readonly IMerchandiseReturnService _merchandiseReturnService;
    private readonly IOrderService _orderService;
    private readonly IProductService _productService;
    private readonly ISalesEmployeeService _salesEmployeeService;
    private readonly IShipmentService _shipmentService;
    private readonly ITranslationService _translationService;
    private readonly IVendorService _vendorService;

    public DocumentViewModelService(
        IDocumentService documentService,
        IDocumentTypeService documentTypeService,
        ICustomerService customerService,
        IOrderService orderService,
        ITranslationService translationService,
        IProductService productService,
        IShipmentService shipmentService,
        IMerchandiseReturnService merchandiseReturnService,
        ICategoryService categoryService,
        ICollectionService collectionService,
        IVendorService vendorService,
        ISalesEmployeeService salesEmployeeService,
        IDownloadService downloadService)
    {
        _documentService = documentService;
        _documentTypeService = documentTypeService;
        _customerService = customerService;
        _orderService = orderService;
        _translationService = translationService;
        _productService = productService;
        _shipmentService = shipmentService;
        _merchandiseReturnService = merchandiseReturnService;
        _categoryService = categoryService;
        _collectionService = collectionService;
        _vendorService = vendorService;
        _salesEmployeeService = salesEmployeeService;
        _downloadService = downloadService;
    }

    public virtual async Task<(IEnumerable<DocumentModel> documetListModel, int totalCount)> PrepareDocumentListModel(
        DocumentListModel model, int pageIndex, int pageSize)
    {
        var documents = await _documentService.GetAll(model.SearchName, model.SearchNumber,
            model.SearchEmail, reference: (Reference)model.Reference, objectId: model.ObjectId, status: model.StatusId,
            pageIndex: pageIndex - 1, pageSize: pageSize);

        var documentListModel = new List<DocumentModel>();
        foreach (var x in documents)
        {
            var docModel = x.ToModel();
            documentListModel.Add(docModel);
        }

        return (documentListModel, documents.TotalCount);
    }

    public virtual async Task<DocumentModel> PrepareDocumentModel(DocumentModel documentModel, Document document,
        SimpleDocumentModel simpleModel)
    {
        var model = documentModel ?? new DocumentModel { Published = true };
        if (document != null)
        {
            model = document.ToModel();
        }
        else
        {
            if (simpleModel != null)
            {
                model.ReferenceId = simpleModel.Reference;
                model.ObjectId = simpleModel.ObjectId;
                if (!string.IsNullOrEmpty(simpleModel.CustomerId))
                    model.CustomerEmail = (await _customerService.GetCustomerById(simpleModel.CustomerId))?.Email;

                if (!string.IsNullOrEmpty(simpleModel.ObjectId))
                    switch (simpleModel.Reference)
                    {
                        case (int)Reference.Order:
                            var order = await _orderService.GetOrderById(simpleModel.ObjectId);
                            if (order != null)
                            {
                                model.Number = order.OrderNumber.ToString();
                                model.TotalAmount = order.OrderTotal;
                                model.OutstandAmount =
                                    order.PaymentStatusId == PaymentStatus.Paid ? 0 : order.OrderTotal;
                                model.CurrencyCode = order.CustomerCurrencyCode;
                                model.Name = string.Format(_translationService.GetResource("Order.Document"),
                                    model.Number);
                                model.DocDate = order.CreatedOnUtc;
                                model.DueDate = order.CreatedOnUtc;
                                model.Quantity = 1;
                                model.Username = $"{order.BillingAddress?.FirstName} {order.BillingAddress?.LastName}";
                                model.CustomerEmail = order.CustomerEmail;
                            }

                            break;
                        case (int)Reference.Product:
                            var product = await _productService.GetProductById(simpleModel.ObjectId);
                            if (product != null)
                            {
                                model.Name = product.Name;
                                model.Number = product.Sku;
                                model.Quantity = 1;
                            }

                            break;
                        case (int)Reference.Category:
                            var category = await _categoryService.GetCategoryById(simpleModel.ObjectId);
                            if (category != null)
                            {
                                model.Name = category.Name;
                                model.Quantity = 1;
                            }

                            break;
                        case (int)Reference.Collection:
                            var collection = await _collectionService.GetCollectionById(simpleModel.ObjectId);
                            if (collection != null)
                            {
                                model.Name = collection.Name;
                                model.Quantity = 1;
                            }

                            break;
                        case (int)Reference.Vendor:
                            var vendor = await _vendorService.GetVendorById(simpleModel.ObjectId);
                            if (vendor != null)
                            {
                                model.Name = vendor.Name;
                                model.Quantity = 1;
                            }

                            break;
                        case (int)Reference.Shipment:
                            var shipment = await _shipmentService.GetShipmentById(simpleModel.ObjectId);
                            if (shipment != null)
                            {
                                model.DocDate = shipment.CreatedOnUtc;
                                model.Number = shipment.ShipmentNumber.ToString();
                                model.Name = string.Format(_translationService.GetResource("Shipment.Document"),
                                    shipment.ShipmentNumber);
                                var sorder = await _orderService.GetOrderById(shipment.OrderId);
                                if (sorder != null)
                                {
                                    model.CustomerId = sorder.CustomerId;
                                    model.CustomerEmail = sorder.CustomerEmail;
                                }
                            }

                            break;
                        case (int)Reference.MerchandiseReturn:
                            var merchandisereturn =
                                await _merchandiseReturnService.GetMerchandiseReturnById(simpleModel.ObjectId);
                            if (merchandisereturn != null)
                            {
                                model.DocDate = merchandisereturn.CreatedOnUtc;
                                model.Number = merchandisereturn.ReturnNumber.ToString();
                                model.Name =
                                    string.Format(_translationService.GetResource("MerchandiseReturns.Document"),
                                        merchandisereturn.ReturnNumber);
                                var sorder = await _orderService.GetOrderById(merchandisereturn.OrderId);
                                if (sorder != null)
                                {
                                    model.CustomerId = sorder.CustomerId;
                                    model.CustomerEmail = sorder.CustomerEmail;
                                }
                            }

                            break;
                    }
            }
        }

        //fill document types
        var types = await _documentTypeService.GetAll();
        foreach (var item in types)
            model.AvailableDocumentTypes.Add(new SelectListItem {
                Text = item.Name,
                Value = item.Id
            });

        //fill sales employees
        model.AvailableSelesEmployees.Add(new SelectListItem {
            Text = _translationService.GetResource("Admin.Documents.Document.Fields.SeId.None"),
            Value = ""
        });
        var salesEmployees = await _salesEmployeeService.GetAll();
        foreach (var item in salesEmployees.Where(x => x.Active))
            model.AvailableSelesEmployees.Add(new SelectListItem {
                Text = item.Name,
                Value = item.Id
            });
        return model;
    }

    public virtual async Task<Document> InsertDocument(DocumentModel model)
    {
        model.CustomerId = !string.IsNullOrEmpty(model.CustomerEmail)
            ? (await _customerService.GetCustomerByEmail(model.CustomerEmail))?.Id
            : string.Empty;

        var document = model.ToEntity();
        await _documentService.Insert(document);
        return document;
    }

    public virtual async Task<Document> UpdateDocument(Document document, DocumentModel model)
    {
        var prevAttachmentId = document.DownloadId;

        if (!string.IsNullOrEmpty(model.CustomerEmail))
        {
            model.CustomerEmail = model.CustomerEmail.ToLowerInvariant();
            model.CustomerId = (await _customerService.GetCustomerByEmail(model.CustomerEmail))?.Id;
        }
        else
        {
            model.CustomerId = string.Empty;
        }

        document = model.ToEntity(document);
        await _documentService.Update(document);

        //delete an old "attachment" file (if deleted or updated)
        if (!string.IsNullOrEmpty(prevAttachmentId) && prevAttachmentId != document.DownloadId)
        {
            var prevAttachment = await _downloadService.GetDownloadById(prevAttachmentId);
            if (prevAttachment != null)
                await _downloadService.DeleteDownload(prevAttachment);
        }

        return document;
    }

    public virtual async Task DeleteDocument(Document document)
    {
        await _documentService.Delete(document);

        //delete an old "attachment" file
        if (!string.IsNullOrEmpty(document.DownloadId))
        {
            var prevAttachment = await _downloadService.GetDownloadById(document.DownloadId);
            if (prevAttachment != null)
                await _downloadService.DeleteDownload(prevAttachment);
        }
    }
}