using Lada.Framework.Data.Domains.Orders;
using Lada.Framework.Data.Enums;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.Enums;
using Lada.Framework.Infrastructures;
using Lada.Framework.Infrastructures.Helpers;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Orders;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Orders.Shared;
using Ladaer.BackEnd.Infrastructures.Services.Crm;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;

namespace Ladaer.BackEnd.Infrastructures.Services.Orders
{
    /// <summary>
    /// Giao diện cho dịch vụ quản lý kiện hàng trong đơn hàng.
    /// </summary>
    public interface IOrderPackageService
    {
        /// <summary>
        /// Lấy thông tin kiện hàng theo ID đơn hàng.
        /// </summary>
        /// <param name="orderId">ID của đơn hàng.</param>
        /// <returns>Thông tin kiện hàng.</returns>
        Task<UpdateOrderPackageModel> GetByOrderId(int orderId);

        /// <summary>
        /// Lấy thông tin kiện hàng theo ID đơn hàng với thông tin đơn vị đo.
        /// </summary>
        /// <param name="orderId">ID của đơn hàng.</param>
        /// <returns>Thông tin kiện hàng với đơn vị đo.</returns>
        Task<UpdateOrderPackageWithUnitsModel> GetByOrderIdWithUnits(int orderId);

        /// <summary>
        /// Cập nhật thông tin kiện hàng.
        /// </summary>
        /// <param name="model">Model chứa thông tin kiện hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<BaseResult> Update(UpdateOrderPackageModel model);
    }
    /// <summary>
    /// Triển khai dịch vụ quản lý kiện hàng trong đơn hàng.
    /// </summary>
    public class OrderPackageService : IOrderPackageService
    {
        private readonly IRepository<Order> _orderRepository;
        private readonly IRepository<OrderPackage> _orderPackageRepository;
        private readonly IOrderTrackService _orderTrackService;
        private readonly IOrderFinService _orderFinService;
        private readonly ICustomerService _customerService;
        /// <summary>
        /// Khởi tạo một thể hiện của <see cref="OrderPackageService"/>.
        /// </summary>
        /// <param name="orderRepository">Đối tượng IRepository của Order.</param>
        /// <param name="orderPackageRepository">Đối tượng IRepository của OrderPackage.</param>
        /// <param name="orderTrackService">Đối tượng IOrderTrackService.</param>
        /// <param name="orderFinService">Đối tượng IOrderFinService.</param>
        public OrderPackageService(IRepository<Order> orderRepository, IRepository<OrderPackage> orderPackageRepository,
            IOrderTrackService orderTrackService, IOrderFinService orderFinService, ICustomerService customerService)
        {
            _orderRepository = orderRepository;
            _orderPackageRepository = orderPackageRepository;
            _orderTrackService = orderTrackService;
            _orderFinService = orderFinService;
            _customerService = customerService;
        }

        /// <summary>
        /// Lấy thông tin kiện hàng theo ID đơn hàng.
        /// </summary>
        /// <param name="orderId">ID của đơn hàng.</param>
        /// <returns>Thông tin kiện hàng.</returns>
        public async Task<UpdateOrderPackageModel> GetByOrderId(int orderId)
        {
            var result = new UpdateOrderPackageModel() { OrderId = orderId };
            if (orderId > 0)
            {
                var orderPackages = await _orderPackageRepository.Query().Where(c => c.OrderId == orderId).ToListAsync();
                if (orderPackages != null && orderPackages.Any())
                {
                    result.Packages = orderPackages.Select(p => p.ToModel()).ToList();
                }
            }
            return result;
        }

        /// <summary>
        /// Lấy thông tin kiện hàng theo ID đơn hàng với thông tin đơn vị đo.
        /// </summary>
        /// <param name="orderId">ID của đơn hàng.</param>
        /// <returns>Thông tin kiện hàng với đơn vị đo.</returns>
        public async Task<UpdateOrderPackageWithUnitsModel> GetByOrderIdWithUnits(int orderId)
        {
            var result = new UpdateOrderPackageWithUnitsModel() { OrderId = orderId };
            if (orderId > 0)
            {
                var orderPackages = await _orderPackageRepository.Query().Where(c => c.OrderId == orderId).ToListAsync();
                if (orderPackages != null && orderPackages.Any())
                {
                    result.Packages = orderPackages.Select(p => p.ToResponseItem()).ToList();
                }
            }
            return result;
        }

        /// <summary>
        /// Cập nhật thông tin kiện hàng.
        /// </summary>
        /// <param name="model">Model chứa thông tin kiện hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<BaseResult> Update(UpdateOrderPackageModel model)
        {
            var result = new BaseResult();
            if (model.OrderId > 0)
            {
                if (model.Packages != null && model.Packages.Any())
                {
                    var order = await _orderRepository.Query().Include(o => o.Packages).FirstOrDefaultAsync(o => o.Id == model.OrderId);
                    if (order != null && order.Id > 0)
                    {
                        var manager = await _customerService.GetManagerById(order.CustomerId);
                        if (manager.Id != model.UpdatedBy && order.SaleId != model.UpdatedBy)
                        {
                            result.Result = Result.Failed;
                            result.Message = "Bạn không có quyền cập nhật kiện hàng không do mình tạo / quản lý";
                            return result;
                        }

                        if (order.Packages != null && order.Packages.Any())
                        {
                            var currentPackageIds = order.Packages.Select(p => p.Id).ToList();
                            var currentTime = DateTimeHelper.CurrentTime();
                            string oldvalue = JsonConvert.SerializeObject(order.Packages, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });

                            // Xác định các kiện hàng cần được thêm mới
                            var newPackages = model.Packages.Where(p => p.Id == 0).ToList();
                            foreach (var packageModel in model.Packages)
                            {
                                var existingPackage = order.Packages.FirstOrDefault(p => p.Id == packageModel.Id);
                                if (existingPackage != null)
                                {
                                    var dimensionWeight = packageModel.Length * packageModel.Width * packageModel.Height / 6000;
                                    var chargeWeight = dimensionWeight > packageModel.Weight ? dimensionWeight : packageModel.Weight;
                                    // Cập nhật thông tin của kiện hàng
                                    existingPackage.Code = packageModel.Code;
                                    existingPackage.Name = packageModel.Name;
                                    existingPackage.Picture = packageModel.Picture;
                                    existingPackage.Weight = UnitConverter.ConvertWeightToGram(packageModel.Weight);
                                    existingPackage.Length = UnitConverter.ConvertDimensionToMillimeter(packageModel.Length);
                                    existingPackage.Width = UnitConverter.ConvertDimensionToMillimeter(packageModel.Width);
                                    existingPackage.Height = UnitConverter.ConvertDimensionToMillimeter(packageModel.Height);
                                    existingPackage.Quantity = packageModel.Quantity;
                                    existingPackage.SubTotalWeight = UnitConverter.ConvertWeightToGram(chargeWeight * packageModel.Quantity);
                                    existingPackage.Note = packageModel.Note;
                                    existingPackage.UpdatedBy = model.UpdatedBy;
                                    existingPackage.UpdatedByUserName = model.UpdatedByUserName;
                                    existingPackage.UpdatedTime = currentTime;

                                    // Cập nhật kiện hàng trong cơ sở dữ liệu
                                    await _orderPackageRepository.UpdateAsync(existingPackage);

                                    // Loại bỏ kiện hàng này khỏi danh sách các kiện hàng đã tồn tại
                                    currentPackageIds.Remove(existingPackage.Id);
                                }
                                else
                                {
                                    // Thêm mới kiện hàng vào đơn hàng
                                    var dimensionWeight = packageModel.Length * packageModel.Width * packageModel.Height / 6000;
                                    var chargeWeight = dimensionWeight > packageModel.Weight ? dimensionWeight : packageModel.Weight;
                                    var newPackage = new OrderPackage
                                    {
                                        Code = packageModel.Code,
                                        Name = packageModel.Name,
                                        Picture = packageModel.Picture,
                                        Weight = UnitConverter.ConvertWeightToGram(packageModel.Weight),
                                        Length = UnitConverter.ConvertDimensionToMillimeter(packageModel.Length),
                                        Width = UnitConverter.ConvertDimensionToMillimeter(packageModel.Width),
                                        Height = UnitConverter.ConvertDimensionToMillimeter(packageModel.Height),
                                        Quantity = packageModel.Quantity,
                                        SubTotalWeight = UnitConverter.ConvertWeightToGram(chargeWeight * packageModel.Quantity),
                                        Note = packageModel.Note,
                                        OrderId = model.OrderId,
                                        CreatedBy = model.UpdatedBy,
                                        CreatedByUserName = model.UpdatedByUserName,
                                        UpdatedBy = model.UpdatedBy,
                                        UpdatedByUserName = model.UpdatedByUserName,
                                        CreatedTime = currentTime,
                                        UpdatedTime = currentTime
                                    };

                                    await _orderPackageRepository.InsertAsync(newPackage);
                                }
                            }

                            // Xác định và xóa các kiện hàng không còn tồn tại trong danh sách model.Packages
                            foreach (var packageId in currentPackageIds)
                            {
                                var packageToDelete = order.Packages.FirstOrDefault(p => p.Id == packageId);
                                if (packageToDelete != null)
                                {
                                    await _orderPackageRepository.RemoveAsync(packageToDelete);
                                }
                            }

                            #region Tính lại cước
                            await _orderFinService.UpdateOrderFinAsync(model.OrderId, model.UpdatedBy, model.UpdatedByUserName);
                            #endregion

                            #region Hành trình
                            string newvalue = JsonConvert.SerializeObject(order.Packages, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
                            var trackModel = new OrderTrackModel()
                            {
                                OrderId = order.Id,
                                OrderCode = order.Code,
                                Name = "Cập nhật trọng lượng",
                                OrderTrackType = OrderTrackType.ForInternal,
                                TrackActionType = TrackActionType.UpdateWeight,
                                UpdatedBy = model.UpdatedBy,
                                UpdatedByUserName = model.UpdatedByUserName,
                                ActionSource = ActionSource.InternalWeb,
                                PhoneContact = "",
                                DataBefore = oldvalue,
                                DataAfter = newvalue
                            };
                            await _orderTrackService.CreateAsync(trackModel);
                            #endregion
                        }
                    }
                }
                else
                {
                    result.Result = Result.Failed;
                    result.Message = "Thông tin hàng hóa không để trống";
                }
            }
            else
            {
                result.Result = Result.Failed;
                result.Message = "Thông tin đơn hàng không hợp lệ";
            }
            return result;
        }
    }
}
