using Dapper;
using Lada.Framework.Data.Domains;
using Lada.Framework.Data.Domains.Orders;
using Lada.Framework.Data.Enums;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.Infrastructures.Helpers;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Business.Deploy;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Business.Warehouse;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Business.Warehouses;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Orders;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Business;
using Ladaer.BackEnd.Infrastructures.Services.Identity;
using Lada.Framework.Infrastructures.Services;
using Ladaer.BackEnd.Infrastructures.Services.Orders;
using Microsoft.EntityFrameworkCore;
using System.Data;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Identity;

namespace Ladaer.BackEnd.Infrastructures.Services.Business
{
    /// <summary>
    /// Giao diện cho WarehouseService
    /// </summary>
    public interface IWarehouseService
    {
        /// <summary>
        /// Xử lý quá trình nhập kho cho một đơn hàng.
        /// </summary>
        /// <param name="model">Mô hình nhập kho chứa thông tin đơn hàng.</param>
        /// <returns>Kết quả nhập kho chỉ ra kết quả của thao tác.</returns>
        Task<InboundResult> Inbound(InboundModel model);

        /// <summary>
        /// Lấy danh sách tài xế theo ID của đại lý với tùy chọn lọc từ khóa và phân trang.
        /// </summary>
        /// <param name="agencyId">ID của đại lý.</param>
        /// <param name="keyword">Từ khóa tùy chọn để lọc tài xế.</param>
        /// <param name="pageNumber">Số trang cho phân trang.</param>
        /// <param name="pageSize">Kích thước trang cho phân trang.</param>
        /// <returns>Danh sách các đối tượng DriverInfoItem.</returns>
        Task<List<DriverInfoItem>> SearchDriversAsync(int agencyId, string? keyword = null, int pageNumber = 1, int pageSize = 10);


        /// <summary>
        /// Lấy danh sách đơn hàng cần inbound của 1 lái xe
        /// </summary>
        /// <param name="userId">Id của lái xe</param>
        /// <param name="pageNumber">Số trang</param>
        /// <param name="pageSize">Số bản ghi / trang</param>
        /// <returns></returns>
        Task<List<InboundOrderItem>> GetInboundOrdersByDriversAsync(int userId, int pageNumber = 1, int pageSize = 10);



    }

    /// <summary>
    /// Lớp dịch vụ để xử lý các hoạt động của kho hàng.
    /// </summary>
    public class WarehouseService : IWarehouseService
    {
        private readonly IDbConnection _dbConnection;
        private readonly IRepository<OrderOps> _orderOpsRepository;
        private readonly IRepository<Order> _orderRepository;
        private readonly IUserService _userService;
        private readonly IOrderTrackService _orderTrackService;
        private readonly IUnifiedMediaService _unifiedMediaService;

        /// <summary>
        /// Khởi tạo một thể hiện mới của lớp <see cref="WarehouseService"/>.
        /// </summary>
        /// <param name="dbConnection">Kết nối cơ sở dữ liệu.</param>
        /// <param name="orderOpsRepository">Kho lưu trữ các hoạt động đơn hàng.</param>
        /// <param name="orderRepository">Kho lưu trữ đơn hàng.</param>
        /// <param name="orderTrackService">Dịch vụ theo dõi đơn hàng.</param>
        /// <param name="userService">Dịch vụ người dùng.</param>
        public WarehouseService(IDbConnection dbConnection, IRepository<OrderOps> orderOpsRepository, IRepository<Order> orderRepository,
            IOrderTrackService orderTrackService, IUserService userService, IUnifiedMediaService unifiedMediaService)
        {
            _dbConnection = dbConnection;
            _orderOpsRepository = orderOpsRepository;
            _orderRepository = orderRepository;
            _userService = userService;
            _orderTrackService = orderTrackService;
            _unifiedMediaService = unifiedMediaService;
        }

        /// <summary>
        /// Lấy danh sách tài xế theo ID của đại lý với tùy chọn lọc từ khóa và phân trang.
        /// </summary>
        /// <param name="agencyId">ID của đại lý.</param>
        /// <param name="keyword">Từ khóa tùy chọn để lọc tài xế.</param>
        /// <param name="pageNumber">Số trang cho phân trang.</param>
        /// <param name="pageSize">Kích thước trang cho phân trang.</param>
        /// <returns>Danh sách các đối tượng DriverInfoItem.</returns>
        public async Task<List<DriverInfoItem>> SearchDriversAsync(int agencyId, string? keyword = null, int pageNumber = 1, int pageSize = 10)
        {
            var drivers = new List<DriverInfoItem>();
            string storeName = "Inbound_GetDrivers"; // Tên thủ tục lưu trữ

            try
            {
                var parameters = new DynamicParameters();
                parameters.Add("@AgencyId", agencyId);
                parameters.Add("@Keyword", keyword);
                parameters.Add("@PageNumber", pageNumber);
                parameters.Add("@PageSize", pageSize);

                drivers = (await _dbConnection.QueryAsync<DriverInfoItem>(storeName, parameters, commandType: CommandType.StoredProcedure)).ToList();
            }
            catch (Exception ex)
            {
                // Ghi lại thông báo lỗi cụ thể
                var errorMessage = ex.Message;
            }

            return drivers;
        }

        /// <summary>
        /// Lấy danh sách đơn hàng cần inbound của 1 lái xe
        /// </summary>
        /// <param name="userId">Id của lái xe</param>
        /// <param name="pageNumber">Số trang</param>
        /// <param name="pageSize">Số bản ghi / trang</param>
        /// <returns></returns>
        public async Task<List<InboundOrderItem>> GetInboundOrdersByDriversAsync(int userId, int pageNumber = 1, int pageSize = 10)
        {
            var orders = new List<InboundOrderItem>();
            string storeName = "Inbound_GetOrderByDriver"; // Tên thủ tục lưu trữ

            try
            {
                var parameters = new DynamicParameters();
                parameters.Add("@UserId", userId);
                parameters.Add("@PageNumber", pageNumber);
                parameters.Add("@PageSize", pageSize);

                var multi = await _dbConnection.QueryMultipleAsync(storeName, parameters,
                    commandType: CommandType.StoredProcedure);
                orders = multi.Read<InboundOrderItem>().AsList();

                var mediaFiles = multi.Read<MediaItem>().AsList();
                var orderPackages = multi.Read<OrderPackageItem>().AsList();
                var orderAddresses = multi.Read<OrderAddressItem>().AsList();

                if (mediaFiles.Any())
                {
                    foreach (var file in mediaFiles)
                    {
                        file.Path = await _unifiedMediaService.GetUrlBySystemPathAsync(file.Path);
                    }
                }

                var saleIds = orders.Select(i => i.SaleId).ToList();
                var saleItems = new List<StaffItem>();
                if (saleIds != null && saleIds.Any())
                {
                    saleItems = await _userService.GetByListIdAsync(saleIds);
                }


                foreach (var order in orders)
                {
                    if (order.SaleId > 0)
                    {
                        var sale = saleItems.FirstOrDefault(s => s.Id == order.SaleId);
                        if (sale != null && sale.Id > 0)
                        {
                            order.SaleUserName = sale.UserName;
                        }
                    }

                    order.MediaFiles = mediaFiles.FindAll(m => m.OrderId == order.Id);
                    order.OrderPackages = orderPackages.FindAll(p => p.OrderId == order.Id);
                    order.OrderAddresses = orderAddresses.FindAll(a => a.OrderId == order.Id);
                }

                //orders = (await _dbConnection.QueryAsync<InboundOrderItem>(storeName, parameters, commandType: CommandType.StoredProcedure)).ToList();
                //foreach (var order in orders)
                //{
                //    order.MediaFiles = JsonConvert.DeserializeObject<List<MediaItem>>(order.MediaFilesJson) ?? new List<MediaItem>();
                //    Console.WriteLine($"OrderId: {order.Id}, Code: {order.Code}, MediaFiles: {order.MediaFiles.Count}");
                //}
            }
            catch (Exception ex)
            {
                // Ghi lại thông báo lỗi cụ thể
                var errorMessage = ex.Message;
            }

            return orders;
        }

        #region Inbound

        /// <summary>
        /// Xử lý quá trình nhập kho cho một đơn hàng.
        /// </summary>
        /// <param name="model">Mô hình nhập kho chứa thông tin đơn hàng.</param>
        /// <returns>Kết quả nhập kho chỉ ra kết quả của thao tác.</returns>
        public async Task<InboundResult> Inbound(InboundModel model)
        {
            var result = new InboundResult();
            if (model.OrderIds != null && model.OrderIds.Any())
            {
                var orderOpses = await _orderOpsRepository.Query().Where(c => model.OrderIds.Contains(c.Id)).ToListAsync();

                if (orderOpses == null || !orderOpses.Any())
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy đơn hàng yêu cầu";
                    return result;
                }

                var validOrderIds = orderOpses.Select(o => o.Id).ToList();


                var orderCommons = await _orderRepository.Query().Where(c => validOrderIds.Contains(c.Id)).ToListAsync();

                if (orderCommons == null || !orderCommons.Any())
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy đơn hàng yêu cầu";
                    return result;
                }

                var agencyId = await _userService.GetAgencyIdByIdAsync(model.UpdatedBy);

                foreach (var orderOpsItem in orderOpses)
                {
                    var orderOps = orderOpsItem;
                    orderOps.Status = OrderStatus.Received;
                    orderOps.PhysicalStatus = OrderPhysicalStatus.Inbound;
                    orderOps.AgencyId = agencyId;
                    orderOps.PicId = model.UpdatedBy;
                    orderOps.PicUserName = model.UpdatedByUserName;

                    orderOps = (OrderOps)orderOps.UpdateUpdation(model.UpdatedBy, model.UpdatedByUserName);
                    var orderCommon = orderCommons.FirstOrDefault(o => o.Id == orderOps.Id);

                    if (orderCommon == null || orderCommon.Id <= 0)
                    {
                        result.Result = Result.Failed;
                        result.Message = "Không tìm thấy đơn hàng yêu cầu: " + orderOps.Id;
                        return result;
                    }

                    try
                    {
                        var udpResult = await _orderOpsRepository.UpdateAsync(orderOps);
                        if (udpResult <= 0)
                        {
                            result.Result = Result.SystemError;
                            result.Message = "Hệ thống không thể thực hiện yêu cầu lúc này, vui lòng thử lại sau!";
                            return result;
                        }
                        var trackModel = new OrderTrackModel()
                        {
                            OrderId = orderOps.Id,
                            OrderCode = orderCommon.Code,
                            Name = OrderPhysicalStatus.Inbound.GetDescription(),
                            OrderTrackType = OrderTrackType.ForAll,
                            TrackActionType = TrackActionType.Inbound,
                            PicId = model.UpdatedBy,
                            PicUserName = model.UpdatedByUserName,
                            UpdatedBy = model.UpdatedBy,
                            UpdatedByUserName = model.UpdatedByUserName,
                            ActionSource = ActionSource.InternalWeb,
                            PhoneContact = "",
                        };
                        var trackResult = await _orderTrackService.CreateAsync(trackModel);
                    }
                    catch (Exception ex)
                    {
                        result.Result = Result.SystemError;
                        result.Message = ex.ToString();
                    }


                }
            }

            return result;
        }

        #endregion




        #region Utilities

        /// <summary>
        /// Xác thực trạng thái cập nhật của một đơn hàng.
        /// </summary>
        /// <param name="currentStatus">Trạng thái hiện tại của đơn hàng.</param>
        /// <param name="currentPhysicalStatus">Trạng thái vật lý hiện tại của đơn hàng.</param>
        /// <param name="newStatus">Trạng thái mới của đơn hàng.</param>
        /// <param name="newPhysicalStatus">Trạng thái vật lý mới của đơn hàng.</param>
        /// <returns>True nếu cập nhật hợp lệ, ngược lại là false.</returns>
        private bool ValidateUpdateStatus(OrderStatus currentStatus, OrderPhysicalStatus currentPhysicalStatus, OrderStatus newStatus, OrderPhysicalStatus newPhysicalStatus)
        {
            var result = false;
            switch (newStatus)
            {
                case OrderStatus.New:
                    if (currentStatus == OrderStatus.Cancelled && currentPhysicalStatus == OrderPhysicalStatus.Cancelled)
                    {
                        result = true;
                    }
                    break;
                case OrderStatus.Cancelled:
                    if (currentStatus == OrderStatus.New &&
                        (currentPhysicalStatus == OrderPhysicalStatus.WaitToPickup ||
                        currentPhysicalStatus == OrderPhysicalStatus.OnPicking))
                    {
                        result = true;
                    }
                    break;
                case OrderStatus.Received:
                    if (currentStatus == OrderStatus.New &&
                        (currentPhysicalStatus == OrderPhysicalStatus.WaitToPickup ||
                        currentPhysicalStatus == OrderPhysicalStatus.OnPicking))
                    {
                        result = true;
                    }
                    break;
                case OrderStatus.PickupFail:
                    break;
                case OrderStatus.DeliveryFail:
                    break;
                case OrderStatus.Delivered:
                    break;
                case OrderStatus.WaitToReturn:
                    break;
                case OrderStatus.ReturnFail:
                    break;
                case OrderStatus.Returned:
                    break;
                case OrderStatus.Unknown:
                    break;
                default:
                    break;
            }
            return result;
        }

        #endregion
    }
}
