using Lada.Framework.Data.Domains.Crm;
using Lada.Framework.Data.Domains.Finance.Quotations;
using Lada.Framework.Data.Enums;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.Infrastructures.Helpers;
using Ladaer.BackEnd.Infrastructures.AppSettings;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Finances;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Export;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using System.Drawing;
using Route = Lada.Framework.Data.Domains.Finance.Quotations.Route;

namespace Ladaer.BackEnd.Infrastructures.Services.Finances
{
    /// <summary>
    /// Giao diện cho dịch vụ quản lý giá.
    /// </summary>
    public interface IPriceService
    {
        /// <summary>
        /// Lấy danh sách giá mặc định theo loại giá.
        /// </summary>
        /// <param name="priceType">Loại giá.</param>
        /// <returns>Danh sách giá mặc định.</returns>
        Task<PriceListModel> GetDefaultPriceList(PriceType priceType);

        /// <summary>
        /// Cập nhật danh sách giá mặc định.
        /// </summary>
        /// <param name="model">Thông tin danh sách giá.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<BaseResult> UpdateDefaultPriceList(PriceListModel model);

        /// <summary>
        /// Xuất danh sách giá mặc định ra file.
        /// </summary>
        /// <param name="filePath">Đường dẫn file.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<ExportResult> ExportDefaultPriceList(string filePath);
    }



    /// <summary>
    /// Triển khai dịch vụ quản lý giá.
    /// </summary>
    public class PriceService : IPriceService
    {
        private readonly IRepository<Price> _priceRepository;
        private readonly IRepository<Route> _routeRepository;
        private readonly IRepository<Customer> _customerRepository;

        /// <summary>
        /// Khởi tạo một thể hiện của <see cref="PriceService"/>.
        /// </summary>
        /// <param name="priceRepository">Đối tượng IRepository của Price.</param>
        /// <param name="customerRepository">Đối tượng IRepository của Customer.</param>
        /// <param name="routeRepository">Đối tượng IRepository của Route.</param>
        public PriceService(IRepository<Price> priceRepository, IRepository<Customer> customerRepository, IRepository<Route> routeRepository)
        {
            _priceRepository = priceRepository;
            _customerRepository = customerRepository;
            _routeRepository = routeRepository;
        }

        /// <summary>
        /// Lấy danh sách giá mặc định theo loại giá.
        /// </summary>
        /// <param name="priceType">Loại giá.</param>
        /// <returns>Danh sách giá mặc định.</returns>
        public async Task<PriceListModel> GetDefaultPriceList(PriceType priceType)
        {
            var result = new PriceListModel() { PriceType = priceType };
            var defaultCustomer = await _customerRepository.Query().FirstOrDefaultAsync(c => c.IsDefaultCustomer);
            if (defaultCustomer == null || defaultCustomer.Id == 0)
            {
                return result;
            }

            result.CustomerId = defaultCustomer.Id;
            var priceList = await _priceRepository.Query().Where(p => p.CustomerId == defaultCustomer.Id && p.PriceType == priceType).Select(p => p.ToPriceDetailModel()).ToListAsync();
            if (priceList.Any())
            {
                result.PriceList = priceList;
            }

            result.Routes = await _routeRepository.Query().OrderBy(r => r.DisplayOrder).Select(r => r.ToItem()).ToListAsync();

            return result;
        }

        /// <summary>
        /// Cập nhật danh sách giá mặc định.
        /// </summary>
        /// <param name="model">Thông tin danh sách giá.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<BaseResult> UpdateDefaultPriceList(PriceListModel model)
        {
            var result = new BaseResult();
            var defaultCustomer = await _customerRepository.Query().FirstOrDefaultAsync(c => c.IsDefaultCustomer);
            if (defaultCustomer == null || defaultCustomer.Id == 0)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy khách hàng mặc định";
                return result;
            }

            try
            {
                // Lấy ra danh sách pricelist hiện tại
                var priceList = await _priceRepository.Query().Where(p => p.CustomerId == defaultCustomer.Id && p.PriceType == model.PriceType).ToListAsync();
                var existPriceIds = priceList.Select(p => p.Id).ToList();

                if (!model.PriceList.Any())
                {
                    foreach (var priceDeleteItem in priceList)
                    {
                        priceDeleteItem.IsDeleted = true;
                        priceDeleteItem.UpdatedBy = model.UpdatedBy;
                        priceDeleteItem.UpdatedByUserName = model.UpdatedByUserName;
                        priceDeleteItem.UpdatedTime = DateTimeHelper.CurrentTime();
                    }
                    await _priceRepository.UpdateAsync(priceList);
                    return result;
                }

                #region Thêm mới
                var addPriceList = model.PriceList.Where(p => p.Id == 0).ToList();
                if (addPriceList.Any())
                {
                    var priceListForAdd = new List<Price>();
                    foreach (var item in addPriceList)
                    {
                        priceListForAdd.Add(new Price()
                        {
                            Name = "",
                            RouteId = item.RouteId,
                            MinWeight = item.MinWeight * 1000,
                            MaxWeight = item.MaxWeight * 1000,
                            CustomerId = defaultCustomer.Id,
                            PriceType = model.PriceType,
                            Value = item.Value,
                            CreatedBy = model.UpdatedBy,
                            CreatedByUserName = model.UpdatedByUserName,
                            UpdatedBy = model.UpdatedBy,
                            UpdatedByUserName = model.UpdatedByUserName,
                            StepWeight = 5000,
                            CreatedTime = DateTimeHelper.CurrentTime(),
                            UpdatedTime = DateTimeHelper.CurrentTime()
                        });
                    }
                    if (priceListForAdd.Any())
                    {
                        await _priceRepository.InsertAsync(priceListForAdd);
                    }
                }
                #endregion

                #region Cập nhật
                var updatePriceList = model.PriceList.Where(p => p.Id > 0).ToList();
                var priceListForUpdate = new List<Price>();
                foreach (var updatePriceItem in updatePriceList)
                {
                    var priceItem = priceList.FirstOrDefault(p => p.Id == updatePriceItem.Id);
                    if (priceItem != null && priceItem.Id > 0)
                    {
                        priceItem.Value = updatePriceItem.Value;
                        priceItem.UpdatedBy = model.UpdatedBy;
                        priceItem.UpdatedByUserName = model.UpdatedByUserName;
                        priceItem.UpdatedTime = DateTimeHelper.CurrentTime();
                        priceListForUpdate.Add(priceItem);
                    }
                }
                if (priceListForUpdate.Any())
                {
                    await _priceRepository.UpdateAsync(priceListForUpdate);
                }
                #endregion

                #region Xóa
                var modelPriceListIds = model.PriceList.Where(m => m.Id > 0).Select(m => m.Id).ToList();
                if (modelPriceListIds.Any())
                {
                    var priceListDeleteIds = existPriceIds.Except(modelPriceListIds).ToList();
                    if (priceListDeleteIds.Any())
                    {
                        var priceListDelete = priceList.Where(p => priceListDeleteIds.Contains(p.Id)).ToList();
                        if (priceListDelete.Any())
                        {
                            foreach (var priceDeleteItem in priceListDelete)
                            {
                                priceDeleteItem.IsDeleted = true;
                                priceDeleteItem.UpdatedBy = model.UpdatedBy;
                                priceDeleteItem.UpdatedByUserName = model.UpdatedByUserName;
                                priceDeleteItem.UpdatedTime = DateTimeHelper.CurrentTime();
                            }
                            await _priceRepository.UpdateAsync(priceListDelete);
                        }
                    }
                }
                #endregion
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = ex.Message;
            }

            return result;
        }

        /// <summary>
        /// Xuất danh sách giá mặc định ra file.
        /// </summary>
        /// <param name="filePath">Đường dẫn file.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<ExportResult> ExportDefaultPriceList(string filePath)
        {
            var result = new ExportResult();

            var defaultCustomer = await _customerRepository.Query().FirstOrDefaultAsync(c => c.IsDefaultCustomer);
            if (defaultCustomer == null || defaultCustomer.Id == 0)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy khách hàng mặc định";
                return result;
            }

            var priceList = await _priceRepository.Query().Where(p => p.CustomerId == defaultCustomer.Id).ToListAsync();

            if (priceList.Any())
            {
                var routes = await _routeRepository.Query().OrderBy(r => r.DisplayOrder).Select(r => r.ToItem()).ToListAsync();

                var weightRanges = new List<WeightRangeModel>();
                foreach (var price in priceList)
                {
                    var existWeightRange = weightRanges.Any(w => w.Min == price.MinWeight && w.Max == price.MaxWeight);
                    if (!existWeightRange)
                    {
                        weightRanges.Add(new WeightRangeModel() { Min = price.MinWeight, Max = price.MaxWeight });
                    }
                }
                weightRanges = weightRanges.OrderBy(weightRange => weightRange.Min).ToList();

                FileInfo excelFile = new FileInfo(filePath);

                try
                {
                    using (var package = new ExcelPackage(excelFile))
                    {
                        var worksheet = package.Workbook.Worksheets.Add("Giá theo khoảng");
                        var valueStyle = worksheet.Cells["A1"].Style;

                        valueStyle.Font.Name = "Times New Roman";
                        valueStyle.Font.Size = 11; // Kích cỡ font
                        valueStyle.Font.Bold = true; // Đậm
                        valueStyle.HorizontalAlignment = ExcelHorizontalAlignment.Center; // Căn giữa ngang
                        valueStyle.VerticalAlignment = ExcelVerticalAlignment.Center;

                        worksheet.Cells[1, 1].Value = "TUYẾN";
                        worksheet.Cells[1, 1].Style.Font.Name = "Times New Roman";
                        worksheet.Cells[1, 1].Style.Font.Size = 11; // Kích cỡ font
                        worksheet.Cells[1, 1].Style.Font.Bold = true; // Đậm
                        worksheet.Cells[1, 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; // Căn giữa ngang
                        worksheet.Cells[1, 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center;

                        worksheet.Cells[1, 2].Value = "KHOẢNG CÁCH";
                        worksheet.Cells[1, 2].Style.Font.Name = "Times New Roman";
                        worksheet.Cells[1, 2].Style.Font.Size = 11; // Kích cỡ font
                        worksheet.Cells[1, 2].Style.Font.Bold = true; // Đậm
                        worksheet.Cells[1, 2].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; // Căn giữa ngang
                        worksheet.Cells[1, 2].Style.VerticalAlignment = ExcelVerticalAlignment.Center;

                        var weightRangeIndex = 2;
                        foreach (var weightRange in weightRanges)
                        {
                            weightRangeIndex++;
                            worksheet.Cells[1, weightRangeIndex].Value = $"{weightRange.Min / 1000} - {weightRange.Max / 1000} kg";
                            worksheet.Cells[1, weightRangeIndex].Style.Font.Name = "Times New Roman";
                            worksheet.Cells[1, weightRangeIndex].Style.Font.Size = 11; // Kích cỡ font
                            worksheet.Cells[1, weightRangeIndex].Style.Font.Bold = true; // Đậm
                            worksheet.Cells[1, weightRangeIndex].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; // Căn giữa ngang
                            worksheet.Cells[1, weightRangeIndex].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                        }

                        int rowIndex = 2;

                        foreach (var route in routes)
                        {
                            worksheet.Cells[rowIndex, 1].Value = route.Name;
                            worksheet.Cells[rowIndex, 1].Style.Font.Name = "Times New Roman";
                            worksheet.Cells[rowIndex, 1].Style.Font.Size = 11; // Kích cỡ font
                            worksheet.Cells[rowIndex, 1].Style.Font.Bold = true; // Đậm
                            worksheet.Cells[rowIndex, 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; // Căn giữa ngang
                            worksheet.Cells[rowIndex, 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center;

                            worksheet.Cells[rowIndex, 2].Value = $"{route.DistanceMin / 1000} - {route.DistanceMax / 1000} km";
                            worksheet.Cells[rowIndex, 2].Style.Font.Name = "Times New Roman";
                            worksheet.Cells[rowIndex, 2].Style.Font.Size = 11; // Kích cỡ font
                            worksheet.Cells[rowIndex, 2].Style.Font.Bold = true; // Đậm
                            worksheet.Cells[rowIndex, 2].Style.HorizontalAlignment = ExcelHorizontalAlignment.Left; // Căn giữa ngang
                            worksheet.Cells[rowIndex, 2].Style.VerticalAlignment = ExcelVerticalAlignment.Center;

                            var pricesForRoute = priceList.FindAll(p => p.RouteId == route.Id).OrderBy(p => p.MinWeight);
                            foreach (var price in pricesForRoute)
                            {
                                int colIndex = 2;
                                foreach (var weightRange in weightRanges)
                                {
                                    colIndex++;
                                    if (price.MinWeight == weightRange.Min && price.MaxWeight == weightRange.Max)
                                    {
                                        worksheet.Cells[rowIndex, colIndex].Value = price.Value;
                                        worksheet.Cells[rowIndex, colIndex].Style.Font.Name = "Times New Roman";
                                        worksheet.Cells[rowIndex, colIndex].Style.Font.Size = 11; // Kích cỡ font
                                        worksheet.Cells[rowIndex, colIndex].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; // Căn giữa ngang
                                        worksheet.Cells[rowIndex, colIndex].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                                    }
                                }
                            }
                            rowIndex++;
                        }

                        package.Save();

                        result.Url = filePath;
                    }
                }
                catch (Exception ex)
                {
                    result.Result = Result.Failed;
                    result.Message = ex.Message;
                }
            }

            return result;
        }
    }
}
