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;
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.Categories;
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ý địa chỉ đơn hàng.
    /// </summary>
    public interface IOrderAddressService
    {
        /// <summary>
        /// Lấy thông tin địa chỉ đơn hàng theo ID.
        /// </summary>
        /// <param name="id">ID của địa chỉ đơn hàng.</param>
        /// <returns>Thông tin địa chỉ đơn hàng.</returns>
        Task<UpdateOrderAddressModel> GetById(int id);

        /// <summary>
        /// Cập nhật thông tin địa chỉ đơn hàng.
        /// </summary>
        /// <param name="model">Thông tin địa chỉ đơn hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<BaseResult> Update(UpdateOrderAddressModel model);
    }
    /// <summary>
    /// Triển khai dịch vụ quản lý địa chỉ đơn hàng.
    /// </summary>
    public class OrderAddressService : IOrderAddressService
    {
        private readonly IRepository<OrderAddress> _orderAddressRepository;
        private readonly ILocationService _locationService;
        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="OrderAddressService"/>.
        /// </summary>
        /// <param name="orderAddressRepository">Đối tượng IRepository của OrderAddress.</param>
        /// <param name="locationService">Đối tượng ILocationService.</param>
        /// <param name="orderTrackService">Đối tượng IOrderTrackService.</param>
        /// <param name="orderFinService">Đối tượng IOrderFinService.</param>
        public OrderAddressService(IRepository<OrderAddress> orderAddressRepository, ILocationService locationService,
         IOrderTrackService orderTrackService, IOrderFinService orderFinService, ICustomerService customerService)
        {
            _orderAddressRepository = orderAddressRepository;
            _locationService = locationService;
            _orderTrackService = orderTrackService;
            _orderFinService = orderFinService;
            _customerService = customerService;
        }

        /// <summary>
        /// Lấy thông tin địa chỉ đơn hàng theo ID.
        /// </summary>
        /// <param name="id">ID của địa chỉ đơn hàng.</param>
        /// <returns>Thông tin địa chỉ đơn hàng.</returns>
        public async Task<UpdateOrderAddressModel> GetById(int id)
        {
            var result = new UpdateOrderAddressModel();
            if (id <= 0)
            {
                return result;
            }
            var orderAddress = await _orderAddressRepository.Query().FirstOrDefaultAsync(c => c.Id == id);
            if (orderAddress == null || orderAddress.Id <= 0)
            {
                return result;
            }
            result = orderAddress.ToUpdateModel();
            var locationIds = new List<int>();
            if (result.CityId > 0)
            {
                locationIds.Add(result.CityId);
            }
            if (result.DistrictId > 0)
            {
                locationIds.Add(result.DistrictId);
            }
            if (result.WardId > 0)
            {
                locationIds.Add(result.WardId);
            }
            var locations = await _locationService.GetByIds(locationIds);
            if (result.CityId > 0)
            {
                var city = locations.FirstOrDefault(l => l.Id == result.CityId);
                if (city != null && city.Id > 0)
                {
                    result.CityName = city.Name;
                }
            }
            if (result.DistrictId > 0)
            {
                var district = locations.FirstOrDefault(l => l.Id == result.DistrictId);
                if (district != null && district.Id > 0)
                {
                    result.DistrictName = district.Name;
                }
            }
            if (result.WardId > 0)
            {
                var ward = locations.FirstOrDefault(l => l.Id == result.WardId);
                if (ward != null && ward.Id > 0)
                {
                    result.WardName = ward.Name;
                }
            }
            return result;
        }

        /// <summary>
        /// Cập nhật thông tin địa chỉ đơn hàng.
        /// </summary>
        /// <param name="model">Thông tin địa chỉ đơn hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<BaseResult> Update(UpdateOrderAddressModel model)
        {
            var result = new BaseResult();
            var recalculateFee = false; // Có tính lại cước hay không

            var orderAddress = await _orderAddressRepository.Query().Include(oa => oa.Order).FirstOrDefaultAsync(c => c.Id == model.Id);

            string oldvalue = JsonConvert.SerializeObject(orderAddress, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });

            if (orderAddress == null || orderAddress.Id <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy địa chỉ yêu cầu!";
                return result;
            }

            try
            {
                var manager = await _customerService.GetManagerById(orderAddress.Order.CustomerId);
                if (manager.Id != model.UpdatedBy && orderAddress.Order.SaleId != model.UpdatedBy)
                {
                    result.Result = Result.Failed;
                    result.Message = "Bạn không có quyền cập nhật địa chỉ đơn hàng không do mình tạo / quản lý";
                    return result;
                }


                if (orderAddress.WardId != model.WardId)
                {
                    recalculateFee = true;
                }
                orderAddress.Name = model.Name;
                orderAddress.PhoneNumber1 = model.PhoneNumber1;
                orderAddress.PhoneNumber2 = string.IsNullOrEmpty(model.PhoneNumber2) ? "" : model.PhoneNumber2;
                orderAddress.CityId = model.CityId;
                orderAddress.DistrictId = model.DistrictId;
                orderAddress.WardId = model.WardId;
                orderAddress.Address1 = model.Address1;
                orderAddress.Note = model.Note;
                orderAddress.ScheduledTime = model.ScheduledTime;

                orderAddress = orderAddress.UpdateCommonInt(model.UpdatedBy, model.UpdatedByUserName);

                string newvalue = JsonConvert.SerializeObject(orderAddress, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });

                await _orderAddressRepository.UpdateAsync(orderAddress);

                #region Hành trình
                var trackModel = new OrderTrackModel()
                {
                    OrderId = orderAddress.OrderId,
                    OrderCode = orderAddress.Order.Code,
                    Name = string.Empty,
                    OrderTrackType = OrderTrackType.ForAll,
                    TrackActionType = orderAddress.AddressType == AddressType.Source ? TrackActionType.EditSourceAddress : TrackActionType.EditDestAddress,
                    UpdatedBy = model.UpdatedBy,
                    UpdatedByUserName = model.UpdatedByUserName,
                    ActionSource = ActionSource.InternalWeb,
                    PhoneContact = "",
                    DataBefore = oldvalue,
                    DataAfter = newvalue
                };
                await _orderTrackService.CreateAsync(trackModel);
                #endregion

                if (recalculateFee)
                {
                    await _orderFinService.UpdateOrderFinAsync(orderAddress.Order.Id, model.UpdatedBy, model.UpdatedByUserName);
                }
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
            }

            return result;
        }
    }
}
