using System.Data;
using Dapper;
using Lada.Framework.Data.Domains.Categories;
using Lada.Framework.Data.Domains.Medias;
using Lada.Framework.Data.Domains.Orders;
using Lada.Framework.Data.Enums;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.SmartTable;
using Lada.Framework.Infrastructures.Helpers;
using Lada.Framework.Infrastructures.Services;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Business.Deploy;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Identity;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Orders;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Business;
using Ladaer.BackEnd.Infrastructures.DTO.Models.DriverApp;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Orders;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Business;
using Ladaer.BackEnd.Infrastructures.Services.Categories;
using Ladaer.BackEnd.Infrastructures.Services.Identity;
using Ladaer.BackEnd.Infrastructures.Services.Orders;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;

namespace Ladaer.BackEnd.Infrastructures.Services.Business
{
    /// <summary>
    /// Interface cho dịch vụ triển khai
    /// </summary>
    public interface IDeployService
    {
        /// <summary>
        /// Lấy danh sách vị trí triển khai
        /// </summary>
        /// <param name="status">Trạng thái đơn hàng</param>
        /// <param name="physicalStatus">Trạng thái vật lý đơn hàng</param>
        /// <param name="addressType">Loại địa chỉ</param>
        /// <returns>Danh sách vị trí triển khai</returns>
        Task<List<DeployLocationItem>> GetDeployLocations(OrderStatus status, OrderPhysicalStatus physicalStatus, AddressType addressType);

        /// <summary>
        /// Lấy danh sách vị trí triển khai
        /// </summary>
        /// <param name="status">Trạng thái đơn hàng</param>
        /// <param name="physicalStatus">Trạng thái vật lý đơn hàng</param>
        /// <param name="addressType">Loại địa chỉ</param>
        /// <returns>Danh sách vị trí triển khai</returns>
        Task<List<DeployLocationItem>> GetDeployLocations(List<OrderStatus> statuses,
            List<OrderPhysicalStatus> physicalStatuses, AddressType addressType, int? agencyId);

        /// <summary>
        /// Lấy danh sách đơn hàng triển khai
        /// </summary>
        /// <param name="param">Tham số bảng thông minh</param>
        /// <returns>Kết quả bảng thông minh chứa danh sách đơn hàng</returns>
        Task<SmartTableResult<OrderItem>> GetDeployOrders(SmartTableParam param);

        /// <summary>
        /// Gán đơn hàng cho người dùng để lấy hàng
        /// </summary>
        /// <param name="model">Mô hình gán đơn hàng</param>
        /// <returns>Kết quả gán đơn hàng</returns>
        Task<AssignResult> AssignPickup(AssignModel model);

        /// <summary>
        /// Bỏ gán đơn hàng cho người dùng
        /// </summary>
        /// <param name="model">Mô hình bỏ gán đơn hàng</param>
        /// <returns>Kết quả bỏ gán đơn hàng</returns>
        Task<AssignResult> UnAssignPickup(AssignModel model);

        /// <summary>
        /// Lấy danh sách giám sát triển khai
        /// </summary>
        /// <param name="pageNumber">Số trang</param>
        /// <param name="pageSize">Kích thước trang</param>
        /// <returns>Danh sách giám sát triển khai và tổng số bản ghi</returns>
        Task<(List<DeployMonitorItem>, int TotalRecords)> GetDeployMonitor(int pageNumber = 1, int pageSize = 10);

        /// <summary>
        /// Lấy chi tiết đơn hàng triển khai
        /// </summary>
        /// <param name="param">Tham số bảng thông minh</param>
        /// <returns>Kết quả bảng thông minh chứa chi tiết đơn hàng</returns>
        Task<SmartTableResult<OrderItem>> GetDeployDetail(SmartTableParam param);

        /// <summary>
        /// Gán giao hàng
        /// </summary>
        /// <param name="model">Model gán</param>
        /// <returns></returns>
        Task<AssignResult> AssignDelivery(AssignModel model);

        /// <summary>
        /// Gán trung chuyển
        /// </summary>
        /// <param name="model">Model gán</param>
        /// <returns></returns>
        Task<AssignResult> AssignTransit(AssignModel model);

        /// <summary>
        /// Sắp xếp thứ tự hiển thị đơn hàng
        /// </summary>
        /// <param name="model">Danh sách đơn hàng với thứ tự mới</param>
        /// <param name="updatedBy">ID người dùng thao tác</param>
        /// <param name="updatedByUserName">Tên người dùng thao tác</param>
        /// <returns>Kết quả sắp xếp</returns>
        Task<BaseResult> ReorderOrders(ReorderModel model, int updatedBy, string updatedByUserName);
    }

    /// <summary>
    /// Triển khai dịch vụ triển khai
    /// </summary>
    public class DeployService : IDeployService
    {
        private readonly IDbConnection _dbConnection;
        private readonly IRepository<Order> _orderRepository;
        private readonly ILocationService _locationService;
        private readonly IUserService _userService;
        private readonly IOrderTrackService _orderTrackService;
        private readonly IRepository<Media> _mediaRepository;
        private readonly IUnifiedMediaService _unifiedMediaService;

        public DeployService(IDbConnection dbConnection, IRepository<Order> orderRepository, ILocationService locationService, IUserService userService,
            IOrderTrackService orderTrackService, IRepository<Media> mediaRepository, IUnifiedMediaService unifiedMediaService)
        {
            _dbConnection = dbConnection;
            _orderRepository = orderRepository;
            _locationService = locationService;
            _userService = userService;
            _orderTrackService = orderTrackService;
            _mediaRepository = mediaRepository;
            _unifiedMediaService = unifiedMediaService;
        }

        /// <summary>
        /// Lấy danh sách vị trí triển khai
        /// </summary>
        /// <param name="status">Trạng thái đơn hàng</param>
        /// <param name="physicalStatus">Trạng thái vật lý đơn hàng</param>
        /// <param name="addressType">Loại địa chỉ</param>
        /// <returns>Danh sách vị trí triển khai</returns>
        public async Task<List<DeployLocationItem>> GetDeployLocations(OrderStatus status,
            OrderPhysicalStatus physicalStatus, AddressType addressType)
        {
            var locations = new List<DeployLocationItem>();
            string storeName = "Deploy_GetLocation";
            try
            {
                locations = (await _dbConnection.QueryAsync<DeployLocationItem>(storeName, new { Status = status, PhysicalStatus = physicalStatus, AddressType = addressType }, commandType: CommandType.StoredProcedure)).ToList();

            }
            catch (Exception)
            {
            }
            return locations;
        }

        public async Task<List<DeployLocationItem>> GetDeployLocations(List<OrderStatus> statuses,
            List<OrderPhysicalStatus> physicalStatuses, AddressType addressType, int? agencyId)
        {
            var locations = new List<DeployLocationItem>();
            string storeName = "Deploy_GetLocation";
            try
            {
                locations = (await _dbConnection.QueryAsync<DeployLocationItem>(storeName, new { Status = statuses, PhysicalStatus = physicalStatuses, AddressType = addressType, AgencyId = agencyId }, commandType: CommandType.StoredProcedure)).ToList();

            }
            catch (Exception)
            {
            }
            return locations;
        }

        #region GetDeployOrders
        /// <summary>
        /// Lấy danh sách đơn hàng triển khai
        /// </summary>
        /// <param name="param">Tham số bảng thông minh</param>
        /// <returns>Kết quả bảng thông minh chứa danh sách đơn hàng</returns>
        public async Task<SmartTableResult<OrderItem>> GetDeployOrders(SmartTableParam param)
        {
            SmartTableResult<OrderItem> gridData = new SmartTableResult<OrderItem>();
            //var query = _orderRepository.Query().Where(o => o.OrderOps.PicId == 0);
            var query = _orderRepository.Query();
            var validQuery = true;
            if (param != null)
            {
                if (param.Search != null)
                {
                    if (param.Search.PredicateObject != null)
                    {
                        dynamic search = param.Search.PredicateObject;

                        if (search.OrderStatus != null)
                        {
                            var statusId = (OrderStatus)search.OrderStatus;
                            if (statusId > 0)
                            {
                                query = query.Where(x => statusId == x.OrderOps.Status);
                            }
                            else
                            {
                                validQuery = false;
                            }
                        }
                        else
                        {
                            validQuery = false;
                        }

                        if (search.OrderPhysicalStatuses != null)
                        {
                            var statusIds = (JArray)search.OrderPhysicalStatuses;
                            if (statusIds.Any())
                            {
                                var ids = statusIds.ToObject<List<OrderPhysicalStatus>>();
                                query = query.Where(x => ids.Contains(x.OrderOps.PhysicalStatus));
                            }
                            else
                            {
                                validQuery = false;
                            }
                        }
                        else
                        {
                            validQuery = false;
                        }

                        if (search.AddressType != null)
                        {
                            var addressType = (AddressType)search.AddressType;

                            if (search.LocationId != null)
                            {
                                var locationId = (int)search.LocationId;
                                if (locationId > 0)
                                {
                                    query = query.Where(x => x.Addresses != null && x.Addresses.Any(a => a.AddressType == addressType &&
                                             (a.CityId == locationId || a.DistrictId == locationId || a.WardId == locationId)));
                                }
                                else
                                {
                                    query = query.Where(x => x.Addresses != null && x.Addresses.Any(a => a.AddressType == addressType));
                                }

                            }
                            else
                            {
                                validQuery = false;
                            }

                        }
                        else
                        {
                            validQuery = false;
                        }

                    }
                    else
                    {
                        validQuery = false;
                    }
                }
                else
                {
                    validQuery = false;
                }

                if (validQuery)
                {
                    param.Sort = new Sort() { Predicate = "CreatedTime", Reverse = true };
                    gridData = await query
                                        .Include(o => o.OrderFin)
                                        .Include(o => o.OrderOps)
                                        .Include(o => o.Addresses)
                                        .Include(o => o.Packages)
                                        .ToSmartTableResultAsync(param, x => x.ToItem());
                    if (gridData.Items.Any())
                    {
                        var addresses = gridData.Items.SelectMany(i => i.Addresses).ToList();
                        var wardIds = addresses.Where(a => a.WardId > 0).Select(a => a.WardId).Distinct().ToList();
                        var fullAddresss = await _locationService.GetFullAddress(wardIds, 3);

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

                        // Lấy danh sách OrderIds để query media
                        var orderIds = gridData.Items.Select(o => o.Id).ToList();

                        // Lấy tất cả media của các orders này
                        var mediaList = await _mediaRepository.Query()
                            .Where(m => orderIds.Contains(m.OrderId))
                            .OrderBy(m => m.OrderId)
                            .ThenBy(m => m.DisplayOrder)
                            .ThenBy(m => m.CreatedTime)
                            .ToListAsync();

                        foreach (var order in gridData.Items)
                        {
                            if (order.SaleId > 0)
                            {
                                var sale = saleItems.FirstOrDefault(s => s.Id == order.SaleId);
                                if (sale != null && sale.Id > 0)
                                {
                                    order.SaleUserName = sale.UserName;
                                }
                            }
                            int addIndex = 1;
                            foreach (var address in order.Addresses)
                            {
                                if (address.WardId > 0)
                                {
                                    var fullAddress = fullAddresss.FirstOrDefault(f => f.Id == address.WardId);
                                    if (fullAddress != null && fullAddress.Id > 0)
                                    {
                                        address.FullAddress = $"{address.Address1}, {fullAddress.FullAddress}";
                                        if (addIndex == 1)
                                        {
                                            order.RouteName += fullAddress.CityName;
                                        }
                                        else
                                        {
                                            order.RouteName += $" - {fullAddress.CityName}";
                                        }
                                        addIndex++;

                                    }
                                }

                            }

                            // Lấy media của order này
                            var orderMedias = mediaList.Where(m => m.OrderId == order.Id).ToList();
                            order.MediaItems = new List<Ladaer.BackEnd.Infrastructures.DTO.Items.Medias.MediaItem>();

                            foreach (var media in orderMedias)
                            {
                                var mediaItem = new Ladaer.BackEnd.Infrastructures.DTO.Items.Medias.MediaItem
                                {
                                    Id = media.Id,
                                    Url = await _unifiedMediaService.GetUrlBySystemPathAsync(media.SystemPath),
                                    AltText = media.AltText ?? string.Empty,
                                    Caption = media.Caption ?? string.Empty,
                                    DisplayOrder = media.DisplayOrder,
                                    OrderId = media.OrderId,
                                    OrderTrackId = media.OrderTrackId,
                                    OrderPackageId = media.OrderPackageId
                                };
                                order.MediaItems.Add(mediaItem);
                            }
                        }
                    }
                }
            }

            return gridData;
        }
        #endregion

        #region Monitor
        /// <summary>
        /// Lấy danh sách giám sát triển khai
        /// </summary>
        /// <param name="pageNumber">Số trang</param>
        /// <param name="pageSize">Kích thước trang</param>
        /// <returns>Danh sách giám sát triển khai và tổng số bản ghi</returns>
        public async Task<(List<DeployMonitorItem>, int TotalRecords)> GetDeployMonitor(int pageNumber = 1, int pageSize = 10)
        {
            var monitorItems = new List<DeployMonitorItem>();
            var totalRecords = 0;
            string storeName = "Deploy_GetDriverMonitor";
            try
            {
                var parameters = new DynamicParameters();
                parameters.Add("PageNumber", pageNumber);
                parameters.Add("PageSize", pageSize);

                var multi = await _dbConnection.QueryMultipleAsync(storeName, parameters, commandType: CommandType.StoredProcedure);
                totalRecords = await multi.ReadSingleAsync<int>();
                monitorItems = (await multi.ReadAsync<DeployMonitorItem>()).ToList();
            }
            catch (Exception)
            {
            }
            return (monitorItems, totalRecords);
        }

        /// <summary>
        /// Lấy chi tiết đơn hàng triển khai
        /// </summary>
        /// <param name="param">Tham số bảng thông minh</param>
        /// <returns>Kết quả bảng thông minh chứa chi tiết đơn hàng</returns>
        public async Task<SmartTableResult<OrderItem>> GetDeployDetail(SmartTableParam param)
        {
            SmartTableResult<OrderItem> gridData = new SmartTableResult<OrderItem>();
            var query = _orderRepository.Query();
            var validQuery = true;
            if (param != null)
            {
                if (param.Search != null)
                {
                    if (param.Search.PredicateObject != null)
                    {
                        dynamic search = param.Search.PredicateObject;
                        if (search.PicId != null)
                        {
                            int picId = search.PicId;

                            if (picId > 0)
                            {
                                query = query.Where(x =>
                                x.OrderOps.PicId == picId
                                && x.OrderOps.Status != OrderStatus.Cancelled
                                && x.OrderOps.PhysicalStatus != OrderPhysicalStatus.Cancelled);

                                // Lọc theo DeployFilter
                                var selectedFilters = new List<string>();
                                if (search.DeployFilter != null)
                                {
                                    if (search.DeployFilter is JArray jArray)
                                    {
                                        selectedFilters = jArray.ToObject<List<string>>() ?? new List<string>();
                                    }
                                    else
                                    {
                                        string deployFilterStr = (string)search.DeployFilter;
                                        if (!string.IsNullOrWhiteSpace(deployFilterStr))
                                        {
                                            selectedFilters = deployFilterStr.Split(',', StringSplitOptions.RemoveEmptyEntries)
                                                .Select(s => s.Trim())
                                                .ToList();
                                        }
                                    }
                                }

                                if (selectedFilters.Any())
                                {
                                    bool hasPickingUp = selectedFilters.Contains("PickingUp");
                                    bool hasPickedUp = selectedFilters.Contains("PickedUp");
                                    bool hasPickup = selectedFilters.Contains("Pickup");
                                    bool hasDelivering = selectedFilters.Contains("Delivering");
                                    bool hasDelivery = selectedFilters.Contains("Delivery");

                                    query = query.Where(x =>
                                        (hasPickingUp && (
                                            (x.OrderOps.Status == OrderStatus.New && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnPicking)
                                            || (x.OrderOps.Status == OrderStatus.New && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.PickFailed)
                                            || (x.OrderOps.Status == OrderStatus.New && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.AssignedPickup)
                                        ))
                                        || (hasPickedUp && (
                                            x.OrderOps.Status == OrderStatus.Received && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.Picked
                                        ))
                                        || (hasPickup && (
                                            (x.OrderOps.Status == OrderStatus.Received && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.Picked)
                                            || (x.OrderOps.Status == OrderStatus.New && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnPicking)
                                            || (x.OrderOps.Status == OrderStatus.New && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.PickFailed)
                                            || (x.OrderOps.Status == OrderStatus.New && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.AssignedPickup)
                                        ))
                                        || (hasDelivering && (
                                            (x.OrderOps.Status == OrderStatus.Received && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnDelivery)
                                            || (x.OrderOps.Status == OrderStatus.Received && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OutboundForDelivery)
                                            || (x.OrderOps.Status == OrderStatus.DeliveryFail && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OutboundForDelivery)
                                            || (x.OrderOps.Status == OrderStatus.DeliveryFail && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnDelivery)
                                        ))
                                        || (hasDelivery && (
                                            (x.OrderOps.Status == OrderStatus.Received && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnDelivery)
                                            || (x.OrderOps.Status == OrderStatus.Received && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OutboundForDelivery)
                                            || (x.OrderOps.Status == OrderStatus.DeliveryFail && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OutboundForDelivery)
                                            || (x.OrderOps.Status == OrderStatus.DeliveryFail && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnDelivery)
                                        ))
                                    );
                                }
                                else
                                {
                                    // Không truyền filter: lấy tất cả (giữ nguyên logic cũ nhưng bỏ trạng thái đã giao)
                                    query = query.Where(x =>
                                        // Lấy hàng
                                        (x.OrderOps.Status == OrderStatus.Received && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.Picked)
                                        || (x.OrderOps.Status == OrderStatus.New && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnPicking)
                                        || (x.OrderOps.Status == OrderStatus.New && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.PickFailed)
                                        || (x.OrderOps.Status == OrderStatus.New && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.AssignedPickup)
                                        // Giao hàng
                                        || (x.OrderOps.Status == OrderStatus.Received && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnDelivery)
                                        || (x.OrderOps.Status == OrderStatus.Received && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OutboundForDelivery)
                                        || (x.OrderOps.Status == OrderStatus.DeliveryFail && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OutboundForDelivery)
                                        || (x.OrderOps.Status == OrderStatus.DeliveryFail && x.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnDelivery)
                                    );
                                }
                            }
                            else
                            {
                                validQuery = false;
                            }

                        }
                        else
                        {
                            validQuery = false;
                        }

                    }
                    else
                    {
                        validQuery = false;
                    }
                }
                else
                {
                    validQuery = false;
                }

                if (validQuery)
                {
                    // Luôn sắp xếp theo OrderOps.DisplayOrder ASC
                    param.Sort = new Sort { Predicate = "OrderOps.DisplayOrder", Reverse = false };
                    gridData = await query
                                        .Include(o => o.OrderFin)
                                        .Include(o => o.OrderOps)
                                        .Include(o => o.Addresses)
                                        .Include(o => o.Packages)
                                        .ToSmartTableResultAsync(param, x => x.ToItem());
                    if (gridData.Items.Any())
                    {
                        var addresses = gridData.Items.SelectMany(i => i.Addresses).ToList();
                        var wardIds = addresses.Where(a => a.WardId > 0).Select(a => a.WardId).Distinct().ToList();
                        var fullAddresss = await _locationService.GetFullAddress(wardIds, 3);

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

                        // Lấy danh sách OrderIds để query media
                        var orderIds = gridData.Items.Select(o => o.Id).ToList();

                        // Lấy tất cả media của các orders này
                        var mediaList = await _mediaRepository.Query()
                            .Where(m => orderIds.Contains(m.OrderId))
                            .OrderBy(m => m.OrderId)
                            .ThenBy(m => m.DisplayOrder)
                            .ThenBy(m => m.CreatedTime)
                            .ToListAsync();

                        foreach (var order in gridData.Items)
                        {
                            if (order.SaleId > 0)
                            {
                                var sale = saleItems.FirstOrDefault(s => s.Id == order.SaleId);
                                if (sale != null && sale.Id > 0)
                                {
                                    order.SaleUserName = sale.UserName;
                                }
                            }
                            int addIndex = 1;
                            foreach (var address in order.Addresses)
                            {
                                if (address.WardId > 0)
                                {
                                    var fullAddress = fullAddresss.FirstOrDefault(f => f.Id == address.WardId);
                                    if (fullAddress != null && fullAddress.Id > 0)
                                    {
                                        address.FullAddress = $"{address.Address1}, {fullAddress.FullAddress}";
                                        if (addIndex == 1)
                                        {
                                            order.RouteName += fullAddress.CityName;
                                        }
                                        else
                                        {
                                            order.RouteName += $" - {fullAddress.CityName}";
                                        }
                                        addIndex++;

                                    }
                                }

                            }

                            // Lấy media của order này
                            var orderMedias = mediaList.Where(m => m.OrderId == order.Id).ToList();
                            order.MediaItems = new List<Ladaer.BackEnd.Infrastructures.DTO.Items.Medias.MediaItem>();

                            foreach (var media in orderMedias)
                            {
                                var mediaItem = new Ladaer.BackEnd.Infrastructures.DTO.Items.Medias.MediaItem
                                {
                                    Id = media.Id,
                                    Url = await _unifiedMediaService.GetUrlBySystemPathAsync(media.SystemPath),
                                    AltText = media.AltText ?? string.Empty,
                                    Caption = media.Caption ?? string.Empty,
                                    DisplayOrder = media.DisplayOrder,
                                    OrderId = media.OrderId,
                                    OrderTrackId = media.OrderTrackId,
                                    OrderPackageId = media.OrderPackageId
                                };
                                order.MediaItems.Add(mediaItem);
                            }
                        }
                    }
                }
            }

            return gridData;
        }
        #endregion

        /// <summary>
        /// Gán đơn hàng cho người dùng để lấy hàng
        /// </summary>
        /// <param name="model">Mô hình gán đơn hàng</param>
        /// <returns>Kết quả gán đơn hàng</returns>
        public async Task<AssignResult> AssignPickup(AssignModel model)
        {
            var result = new AssignResult();

            var orders = await _orderRepository.Query().Include(o => o.OrderOps).Where(o => model.OrderIds.Contains(o.Id)).ToListAsync();
            var user = await _userService.GetByIdAsync(model.UserId);
            var tracks = new List<OrderTrackModel>();
            var currentTime = DateTimeHelper.CurrentTime();

            var updateMessages = new List<string>();

            if (orders == null || !orders.Any())
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy đơn hàng nào";
                return result;
            }
            if (user == null || user.IsLocked)
            {
                result.Result = Result.Failed;
                result.Message = "Người dùng không hợp lệ hoặc bị khóa";
                return result;
            }
            foreach (var order in orders)
            {
                if (order.OrderOps == null || order.OrderOps.Id <= 0)
                {
                    result.Result = Result.Failed;
                    result.Message = $"Đơn hàng có mã {order.Code} bị lỗi, không tìm thấy thông tin triển khai";
                    return result;
                }
                if ((order.OrderOps.Status == OrderStatus.New || order.OrderOps.Status == OrderStatus.PickupFail)
                    && (order.OrderOps.PhysicalStatus == OrderPhysicalStatus.WaitToPickup || order.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnPicking))
                {
                    order.OrderOps.PhysicalStatus = OrderPhysicalStatus.OnPicking;
                    order.OrderOps.PicId = user.Id;
                    order.OrderOps.PicUserName = user.UserName;
                    order.OrderOps.LastPicId = user.Id;
                    order.OrderOps.LastPicUserName = user.UserName;
                    order.OrderOps.UpdatedBy = model.UpdatedBy;
                    order.OrderOps.UpdatedByUserName = model.UpdatedByUserName;
                    order.UpdatedBy = model.UpdatedBy;
                    order.UpdatedByUserName = model.UpdatedByUserName;
                    order.UpdatedTime = currentTime;
                    order.OrderOps.UpdatedTime = currentTime;

                    var trackModel = new OrderTrackModel()
                    {
                        OrderId = order.Id,
                        OrderCode = order.Code,
                        Name = $"{model.UpdatedByUserName} gán lấy hàng cho {user.UserName}.",
                        OrderTrackType = OrderTrackType.ForInternal,
                        TrackActionType = TrackActionType.AssignPickup,
                        PicId = user.Id,
                        PicUserName = user.UserName,
                        UpdatedBy = model.UpdatedBy,
                        UpdatedByUserName = model.UpdatedByUserName,
                        ActionSource = ActionSource.InternalWeb,
                        PhoneContact = user.PhoneNumber
                    };
                    tracks.Add(trackModel);
                }
                else
                {
                    result.Result = Result.Failed;
                    result.Message = $"Đơn hàng có mã {order.Code} bị lỗi, trạng thái không hợp lệ, trạng thái hiện tại là {order.OrderOps.Status.GetDescription()} và {order.OrderOps.PhysicalStatus.GetDescription()}";
                    return result;
                }
            }

            try
            {
                var updateResult = await _orderRepository.UpdateAsync(orders);
                if (updateResult > 0)
                {
                    await _orderTrackService.CreateAsync(tracks);
                }
            }
            catch (Exception ex)
            {
                throw;
            }

            return result;
        }

        /// <summary>
        /// Bỏ gán đơn hàng cho người dùng
        /// </summary>
        /// <param name="model">Mô hình bỏ gán đơn hàng</param>
        /// <returns>Kết quả bỏ gán đơn hàng</returns>
        public async Task<AssignResult> UnAssignPickup(AssignModel model)
        {
            var result = new AssignResult();

            var orders = await _orderRepository.Query().Include(o => o.OrderOps).Where(o => model.OrderIds.Contains(o.Id)).ToListAsync();
            var user = await _userService.GetByIdAsync(model.UserId);
            var tracks = new List<OrderTrackModel>();
            var currentTime = DateTimeHelper.CurrentTime();

            var updateMessages = new List<string>();

            if (orders == null || !orders.Any())
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy đơn hàng nào";
                return result;
            }
            if (user == null || user.IsLocked)
            {
                result.Result = Result.Failed;
                result.Message = "Người dùng không hợp lệ hoặc bị khóa";
                return result;
            }
            foreach (var order in orders)
            {
                if (order.OrderOps == null || order.OrderOps.Id <= 0)
                {
                    result.Result = Result.Failed;
                    result.Message = $"Đơn hàng có mã {order.Code} bị lỗi, không tìm thấy thông tin triển khai";
                    return result;
                }
                if ((order.OrderOps.Status == OrderStatus.New || order.OrderOps.Status == OrderStatus.PickupFail)
                    && (order.OrderOps.PhysicalStatus == OrderPhysicalStatus.WaitToPickup || order.OrderOps.PhysicalStatus == OrderPhysicalStatus.OnPicking))
                {
                    order.OrderOps.PhysicalStatus = OrderPhysicalStatus.WaitToPickup;
                    order.OrderOps.PicId = 0;
                    order.OrderOps.PicUserName = string.Empty;
                    order.OrderOps.UpdatedBy = model.UpdatedBy;
                    order.OrderOps.UpdatedByUserName = model.UpdatedByUserName;
                    order.UpdatedBy = model.UpdatedBy;
                    order.UpdatedByUserName = model.UpdatedByUserName;
                    order.UpdatedTime = currentTime;
                    order.OrderOps.UpdatedTime = currentTime;

                    var trackModel = new OrderTrackModel()
                    {
                        OrderId = order.Id,
                        OrderCode = order.Code,
                        Name = $"{model.UpdatedByUserName} bỏ gán lấy hàng của {user.UserName}.",
                        OrderTrackType = OrderTrackType.ForInternal,
                        TrackActionType = TrackActionType.Update,
                        PicId = user.Id,
                        PicUserName = user.UserName,
                        UpdatedBy = model.UpdatedBy,
                        UpdatedByUserName = model.UpdatedByUserName,
                        ActionSource = ActionSource.InternalWeb,
                        PhoneContact = user.PhoneNumber
                    };
                    tracks.Add(trackModel);
                }
                else
                {
                    result.Result = Result.Failed;
                    result.Message = $"Đơn hàng có mã {order.Code} bị lỗi, trạng thái không hợp lệ, trạng thái hiện tại là {order.OrderOps.Status.GetDescription()} và {order.OrderOps.PhysicalStatus.GetDescription()}";
                    return result;
                }
            }

            try
            {
                var updateResult = await _orderRepository.UpdateAsync(orders);
                if (updateResult > 0)
                {
                    await _orderTrackService.CreateAsync(tracks);
                }
            }
            catch (Exception ex)
            {
                throw;
            }

            return result;
        }


        #region Delivery
        /// <summary>
        /// Gán đơn hàng cho người dùng để giao hàng
        /// </summary>
        /// <param name="model">Mô hình gán đơn hàng</param>
        /// <returns>Kết quả gán đơn hàng</returns>
        public async Task<AssignResult> AssignDelivery(AssignModel model)
        {
            var result = new AssignResult();

            var orders = await _orderRepository.Query().Include(o => o.OrderOps).Where(o => model.OrderIds.Contains(o.Id)).ToListAsync();
            var user = await _userService.GetByIdAsync(model.UserId);
            var tracks = new List<OrderTrackModel>();
            var currentTime = DateTimeHelper.CurrentTime();

            var updateMessages = new List<string>();

            if (orders == null || !orders.Any())
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy đơn hàng nào";
                return result;
            }
            if (user == null || user.IsLocked)
            {
                result.Result = Result.Failed;
                result.Message = "Người dùng không hợp lệ hoặc bị khóa";
                return result;
            }
            foreach (var order in orders)
            {
                if (order.OrderOps == null || order.OrderOps.Id <= 0)
                {
                    result.Result = Result.Failed;
                    result.Message = $"Đơn hàng có mã {order.Code} bị lỗi, không tìm thấy thông tin triển khai";
                    return result;
                }
                if ((order.OrderOps.Status == OrderStatus.Received || order.OrderOps.Status == OrderStatus.DeliveryFail)
                    && (order.OrderOps.PhysicalStatus == OrderPhysicalStatus.Inbound || order.OrderOps.PhysicalStatus == OrderPhysicalStatus.Outbound))
                {
                    order.OrderOps.PhysicalStatus = OrderPhysicalStatus.OnDelivery;
                    order.OrderOps.PicId = user.Id;
                    order.OrderOps.PicUserName = user.UserName;
                    order.OrderOps.LastPicId = user.Id;
                    order.OrderOps.LastPicUserName = user.UserName;
                    order.OrderOps.UpdatedBy = model.UpdatedBy;
                    order.OrderOps.UpdatedByUserName = model.UpdatedByUserName;
                    order.UpdatedBy = model.UpdatedBy;
                    order.UpdatedByUserName = model.UpdatedByUserName;
                    order.UpdatedTime = currentTime;
                    order.OrderOps.UpdatedTime = currentTime;

                    var trackModel = new OrderTrackModel()
                    {
                        OrderId = order.Id,
                        OrderCode = order.Code,
                        Name = $"{model.UpdatedByUserName} gán giao hàng cho {user.UserName}.",
                        OrderTrackType = OrderTrackType.ForInternal,
                        TrackActionType = TrackActionType.AssignDelivery,
                        PicId = user.Id,
                        PicUserName = user.UserName,
                        UpdatedBy = model.UpdatedBy,
                        UpdatedByUserName = model.UpdatedByUserName,
                        ActionSource = ActionSource.InternalWeb,
                        PhoneContact = user.PhoneNumber
                    };
                    tracks.Add(trackModel);
                }
                else
                {
                    result.Result = Result.Failed;
                    result.Message = $"Đơn hàng có mã {order.Code} bị lỗi, trạng thái không hợp lệ, trạng thái hiện tại là {order.OrderOps.Status.GetDescription()} và {order.OrderOps.PhysicalStatus.GetDescription()}";
                    return result;
                }
            }

            try
            {
                var updateResult = await _orderRepository.UpdateAsync(orders);
                if (updateResult > 0)
                {
                    await _orderTrackService.CreateAsync(tracks);
                }
            }
            catch (Exception ex)
            {
                throw;
            }

            return result;
        }
        #endregion


        #region Transit
        /// <summary>
        /// Gán đơn hàng cho người dùng để giao hàng
        /// </summary>
        /// <param name="model">Mô hình gán đơn hàng</param>
        /// <returns>Kết quả gán đơn hàng</returns>
        public async Task<AssignResult> AssignTransit(AssignModel model)
        {
            var result = new AssignResult();

            var orders = await _orderRepository.Query().Include(o => o.OrderOps).Where(o => model.OrderIds.Contains(o.Id)).ToListAsync();
            var user = await _userService.GetByIdAsync(model.UserId);
            var tracks = new List<OrderTrackModel>();
            var currentTime = DateTimeHelper.CurrentTime();

            var updateMessages = new List<string>();

            if (orders == null || !orders.Any())
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy đơn hàng nào";
                return result;
            }
            if (user == null || user.IsLocked)
            {
                result.Result = Result.Failed;
                result.Message = "Người dùng không hợp lệ hoặc bị khóa";
                return result;
            }
            foreach (var order in orders)
            {
                if (order.OrderOps == null || order.OrderOps.Id <= 0)
                {
                    result.Result = Result.Failed;
                    result.Message = $"Đơn hàng có mã {order.Code} bị lỗi, không tìm thấy thông tin triển khai";
                    return result;
                }
                if ((order.OrderOps.Status == OrderStatus.Received || order.OrderOps.Status == OrderStatus.DeliveryFail)
                    && (order.OrderOps.PhysicalStatus == OrderPhysicalStatus.Inbound || order.OrderOps.PhysicalStatus == OrderPhysicalStatus.Picked))
                {
                    order.OrderOps.PhysicalStatus = OrderPhysicalStatus.Outbound;
                    order.OrderOps.PicId = user.Id;
                    order.OrderOps.PicUserName = user.UserName;
                    order.OrderOps.LastPicId = user.Id;
                    order.OrderOps.LastPicUserName = user.UserName;
                    order.OrderOps.UpdatedBy = model.UpdatedBy;
                    order.OrderOps.UpdatedByUserName = model.UpdatedByUserName;
                    order.UpdatedBy = model.UpdatedBy;
                    order.UpdatedByUserName = model.UpdatedByUserName;
                    order.UpdatedTime = currentTime;
                    order.OrderOps.UpdatedTime = currentTime;

                    var trackModel = new OrderTrackModel()
                    {
                        OrderId = order.Id,
                        OrderCode = order.Code,
                        Name = $"{model.UpdatedByUserName} xuất hàng cho {user.UserName}.",
                        OrderTrackType = OrderTrackType.ForInternal,
                        TrackActionType = TrackActionType.Outbound,
                        PicId = user.Id,
                        PicUserName = user.UserName,
                        UpdatedBy = model.UpdatedBy,
                        UpdatedByUserName = model.UpdatedByUserName,
                        ActionSource = ActionSource.InternalWeb,
                        PhoneContact = user.PhoneNumber
                    };
                    tracks.Add(trackModel);
                }
                else
                {
                    result.Result = Result.Failed;
                    result.Message = $"Đơn hàng có mã {order.Code} bị lỗi, trạng thái không hợp lệ, trạng thái hiện tại là {order.OrderOps.Status.GetDescription()} và {order.OrderOps.PhysicalStatus.GetDescription()}";
                    return result;
                }
            }

            try
            {
                var updateResult = await _orderRepository.UpdateAsync(orders);
                if (updateResult > 0)
                {
                    await _orderTrackService.CreateAsync(tracks);
                }
            }
            catch (Exception ex)
            {
                throw;
            }

            return result;
        }
        #endregion

        /// <summary>
        /// Sắp xếp thứ tự hiển thị đơn hàng
        /// </summary>
        /// <param name="model">Danh sách đơn hàng với thứ tự mới</param>
        /// <param name="updatedBy">ID người dùng thao tác</param>
        /// <param name="updatedByUserName">Tên người dùng thao tác</param>
        /// <returns>Kết quả sắp xếp</returns>
        public async Task<BaseResult> ReorderOrders(ReorderModel model, int updatedBy, string updatedByUserName)
        {
            var result = new BaseResult { Result = Result.Success };

            if (model.Items == null || !model.Items.Any())
            {
                result.Result = Result.Failed;
                result.Message = "Danh sách sắp xếp không được để trống";
                return result;
            }

            try
            {
                var orderIds = model.Items.Select(i => i.OrderId).ToList();

                var orders = await _orderRepository.Query()
                    .Include(o => o.OrderOps)
                    .Where(o => orderIds.Contains(o.Id))
                    .ToListAsync();

                if (!orders.Any())
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy đơn hàng nào để sắp xếp";
                    return result;
                }

                var currentTime = DateTimeHelper.CurrentTime();

                foreach (var item in model.Items)
                {
                    var order = orders.FirstOrDefault(o => o.Id == item.OrderId);
                    if (order != null && order.OrderOps != null)
                    {
                        order.OrderOps.DisplayOrder = item.DisplayOrder;
                        order.OrderOps.UpdatedBy = updatedBy;
                        order.OrderOps.UpdatedByUserName = updatedByUserName;
                        order.OrderOps.UpdatedTime = currentTime;

                        order.UpdatedBy = updatedBy;
                        order.UpdatedByUserName = updatedByUserName;
                        order.UpdatedTime = currentTime;
                    }
                }

                await _orderRepository.UpdateAsync(orders);
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi hệ thống khi lưu thứ tự hiển thị: {ex.Message}";
            }

            return result;
        }
    }
}
