using Lada.Framework.Data.Domains;
using Lada.Framework.Data.Domains.Categories;
using Lada.Framework.Data.Domains.Crm;
using Lada.Framework.Data.Enums;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.SmartTable;
using Lada.Framework.Infrastructures;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Crm;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Categories;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Crm;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Crm;
using Ladaer.BackEnd.Infrastructures.Services.Categories;
using Microsoft.EntityFrameworkCore;

namespace Ladaer.BackEnd.Infrastructures.Services.Crm
{
    /// <summary>
    /// Giao diện cho dịch vụ quản lý địa chỉ khách hàng.
    /// </summary>
    public interface ICustomerAddressService
    {
        /// <summary>
        /// Tìm kiếm địa chỉ khách hàng.
        /// </summary>
        /// <param name="param">Thông số tìm kiếm.</param>
        /// <returns>Kết quả tìm kiếm địa chỉ khách hàng.</returns>
        Task<SmartTableResult<CustomerAddressItem>> Search(SmartTableParam param);

        /// <summary>
        /// Gợi ý địa chỉ khách hàng.
        /// </summary>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <param name="customerId">Id của khách hàng.</param>
        /// <param name="addressType">Loại địa chỉ.</param>
        /// <returns>Danh sách địa chỉ khách hàng gợi ý.</returns>
        Task<List<CustomerAddressItem>> Suggest(string keyword, int customerId, AddressType addressType);

        /// <summary>
        /// Tạo hoặc cập nhật địa chỉ khách hàng.
        /// </summary>
        /// <param name="model">Thông tin địa chỉ khách hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<CustomerAddressResult> CreateOrUpdate(CustomerAddressModel model);

        /// <summary>
        /// Lấy thông tin địa chỉ khách hàng theo Id.
        /// </summary>
        /// <param name="id">Id của địa chỉ khách hàng.</param>
        /// <returns>Thông tin địa chỉ khách hàng.</returns>
        Task<CustomerAddressModel> GetById(int id);

        /// <summary>
        /// Xóa địa chỉ khách hàng.
        /// </summary>
        /// <param name="id">Id của địa chỉ khách hàng.</param>
        /// <param name="currentUser">Thông tin người dùng hiện tại.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<BaseResult> Delete(int id, CurrentUser currentUser);

        /// <summary>
        /// Cập nhật địa chỉ khách hàng.
        /// </summary>
        /// <param name="id">Id của địa chỉ khách hàng.</param>
        /// <param name="model">Thông tin địa chỉ khách hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<bool> UpdateCustomerAddress(int id, CustomerAddressModel model);
    }
    /// <summary>
    /// Triển khai dịch vụ quản lý địa chỉ khách hàng.
    /// </summary>
    public class CustomerAddressService : ICustomerAddressService
    {
        private readonly IRepository<CustomerAddress> _customerAddressRepository;
        private readonly IRepository<Location> _locationRepository;
        private readonly ILocationService _locationService;

        /// <summary>
        /// Khởi tạo một thể hiện của <see cref="CustomerAddressService"/>.
        /// </summary>
        /// <param name="customerAddressRepository">Đối tượng IRepository của CustomerAddress.</param>
        /// <param name="locationRepository">Đối tượng IRepository của Location.</param>
        /// <param name="locationService">Đối tượng ILocationService.</param>
        public CustomerAddressService(IRepository<CustomerAddress> customerAddressRepository, IRepository<Location> locationRepository, ILocationService locationService)
        {
            _customerAddressRepository = customerAddressRepository;
            _locationRepository = locationRepository;
            _locationService = locationService;
        }

        #region Search
        /// <summary>
        /// Tìm kiếm địa chỉ khách hàng.
        /// </summary>
        /// <param name="param">Thông số tìm kiếm.</param>
        /// <returns>Kết quả tìm kiếm địa chỉ khách hàng.</returns>
        public async Task<SmartTableResult<CustomerAddressItem>> Search(SmartTableParam param)
        {
            var query = _customerAddressRepository.Query();
            int maxQuery = 100;
            if (param.Pagination.PageSize > maxQuery)
            {
                param.Pagination.PageSize = maxQuery;
            }
            if (param.Search.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;
                if (search.CustomerId != null)
                {
                    int customerId = search.CustomerId;
                    query = query.Where(x => x.CustomerId == customerId);
                }

                if (search.Keyword != null)
                {
                    string keyword = search.Keyword;
                    keyword = keyword.Trim().ToLower();
                    if (!string.IsNullOrEmpty(keyword))
                    {
                        query = query.Where(x => x.ContactName.ToLower().Contains(keyword)
                                    || x.ContactPhoneNumber.ToLower().Contains(keyword)
                                    || x.Address.ToLower().Contains(keyword));
                    }
                }

                if (search.AddressType != null)
                {
                    AddressType addressType = search.AddressType;
                    query = query.Where(x => x.AddressType == addressType);
                }
            }
            param.Sort = new Sort() { Predicate = "Id", Reverse = false };
            var gridData = await query.ToSmartTableResultAsync(param, x => x.ToItem());
            if (gridData.Items.Any())
            {
                var wardIds = gridData.Items.Where(a => a.WardId > 0).Select(a => a.WardId).Distinct().ToList();
                var fullAddresss = await _locationService.GetFullAddress(wardIds, 3);

                foreach (var item in gridData.Items)
                {
                    if (item.WardId > 0)
                    {
                        var fullAddress = fullAddresss.FirstOrDefault(f => f.Id == item.WardId);
                        if (fullAddress != null && fullAddress.Id > 0)
                        {
                            item.FullAddress = item.Address + ", " + fullAddress.FullAddress;
                        }
                    }
                }
            }
            return gridData;
        }

        /// <summary>
        /// Gợi ý địa chỉ khách hàng.
        /// </summary>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <param name="customerId">Id của khách hàng.</param>
        /// <param name="addressType">Loại địa chỉ.</param>
        /// <returns>Danh sách địa chỉ khách hàng gợi ý.</returns>
        public async Task<List<CustomerAddressItem>> Suggest(string keyword, int customerId, AddressType addressType)
        {
            var result = new List<CustomerAddressItem>();
            var limit = 25;
            var query = _customerAddressRepository.Query().Where(c => c.CustomerId == customerId && c.AddressType == addressType);
            keyword = !string.IsNullOrEmpty(keyword) ? keyword.Trim().ToLower() : "";
            if (!string.IsNullOrEmpty(keyword))
            {
                query = query.Where(c => (!string.IsNullOrEmpty(c.ContactPhoneNumber) && c.ContactPhoneNumber.Contains(keyword))
                || (!string.IsNullOrEmpty(c.ContactName) && c.ContactName.Contains(keyword))
                || (!string.IsNullOrEmpty(c.Address) && c.Address.Contains(keyword))
                );
            }
            result = query.OrderByDescending(c => c.CreatedTime).Take(limit).Select(c => c.ToItem()).ToList();

            return result;
        }
        #endregion

        #region CRUD
        /// <summary>
        /// Tạo hoặc cập nhật địa chỉ khách hàng.
        /// </summary>
        /// <param name="model">Thông tin địa chỉ khách hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<CustomerAddressResult> CreateOrUpdate(CustomerAddressModel model)
        {
            var customerAddress = model.ToEntity();

            // Cập nhật thông tin chung của thực thể
            customerAddress = customerAddress.UpdateCommonInt(model.UpdatedBy, model.UpdatedByUserName);

            if (customerAddress.Id > 0)
            {
                // Cập nhật
                return await Update(customerAddress);
            }
            else
            {
                // Thêm mới
                return await Create(customerAddress);
            }
        }

        /// <summary>
        /// Cập nhật địa chỉ khách hàng.
        /// </summary>
        /// <param name="customerAddress">Thông tin địa chỉ khách hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        private async Task<CustomerAddressResult> Update(CustomerAddress customerAddress)
        {
            var result = new CustomerAddressResult() { Result = Result.Success };
            var customerAddressForUpdate = await _customerAddressRepository.Query().FirstOrDefaultAsync(c => c.Id == customerAddress.Id);
            if (customerAddressForUpdate == null || customerAddress.Id <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy khách hàng yêu cầu!";
                return result;
            }

            try
            {
                customerAddressForUpdate.ContactName = customerAddress.ContactName;
                customerAddressForUpdate.ContactPhoneNumber = customerAddress.ContactPhoneNumber;
                customerAddressForUpdate.Address = customerAddress.Address;
                customerAddressForUpdate.CityId = customerAddress.CityId;
                customerAddressForUpdate.DistrictId = customerAddress.DistrictId;
                customerAddressForUpdate.WardId = customerAddress.WardId;
                customerAddressForUpdate.Note = customerAddress.Note;

                // Cập nhật thông tin chung của thực thể
                customerAddressForUpdate = customerAddressForUpdate.UpdateCommonInt();

                await _customerAddressRepository.UpdateAsync(customerAddressForUpdate);
                result.Id = customerAddressForUpdate.Id;
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
            }
            return result;
        }

        /// <summary>
        /// Thêm mới địa chỉ khách hàng.
        /// </summary>
        /// <param name="customerAddress">Thông tin địa chỉ khách hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        private async Task<CustomerAddressResult> Create(CustomerAddress customerAddress)
        {
            var result = new CustomerAddressResult();
            try
            {
                await _customerAddressRepository.InsertAsync(customerAddress);
                result.Id = customerAddress.Id;
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
                result.Id = 0;
            }
            return result;
        }
        #endregion

        /// <summary>
        /// Lấy thông tin địa chỉ khách hàng theo Id.
        /// </summary>
        /// <param name="id">Id của địa chỉ khách hàng.</param>
        /// <returns>Thông tin địa chỉ khách hàng.</returns>
        public async Task<CustomerAddressModel> GetById(int id)
        {
            var result = new CustomerAddressModel();
            if (id <= 0)
            {
                return result;
            }
            var customerAddress = await _customerAddressRepository.Query().FirstOrDefaultAsync(c => c.Id == id);
            if (customerAddress == null || customerAddress.Id <= 0)
            {
                return result;
            }
            var customerAddressModel = customerAddress.MapTo<CustomerAddress, CustomerAddressModel>();
            var fullAddress = "";
            if (customerAddressModel.WardId > 0)
            {
                fullAddress = await _locationService.GetFullAddress(customerAddressModel.WardId, 3);
            }
            else if (customerAddressModel.DistrictId > 0)
            {
                fullAddress = await _locationService.GetFullAddress(customerAddressModel.DistrictId, 2);
            }
            else if (customerAddressModel.CityId > 0)
            {
                fullAddress = await _locationService.GetFullAddress(customerAddressModel.CityId, 1);
            }
            customerAddressModel.FullAddress = $"{customerAddressModel.Address}, {fullAddress}";

            return customerAddressModel;
        }

        /// <summary>
        /// Xóa địa chỉ khách hàng.
        /// </summary>
        /// <param name="id">Id của địa chỉ khách hàng.</param>
        /// <param name="currentUser">Thông tin người dùng hiện tại.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<BaseResult> Delete(int id, CurrentUser currentUser)
        {
            var result = new BaseResult() { Result = Result.Success };
            var customerAddressForUpdate = await _customerAddressRepository.Query().FirstOrDefaultAsync(c => c.Id == id);
            if (customerAddressForUpdate == null)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy bản ghi yêu cầu";
                return result;
            }

            try
            {
                customerAddressForUpdate.IsDeleted = true;
                customerAddressForUpdate = customerAddressForUpdate.UpdateCommonInt(currentUser.UserId, currentUser.UserName);
                await _customerAddressRepository.UpdateAsync(customerAddressForUpdate);
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.Message;
            }

            return result;
        }

        /// <summary>
        /// Cập nhật địa chỉ khách hàng.
        /// </summary>
        /// <param name="id">Id của địa chỉ khách hàng.</param>
        /// <param name="model">Thông tin địa chỉ khách hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<bool> UpdateCustomerAddress(int id, CustomerAddressModel model)
        {
            var customerAddressForUpdate = await _customerAddressRepository.Query().FirstOrDefaultAsync(c => c.Id == id);
            if (customerAddressForUpdate == null)
            {
                return false;
            }

            try
            {
                customerAddressForUpdate.ContactName = model.ContactName;
                customerAddressForUpdate.ContactPhoneNumber = model.ContactPhoneNumber;
                customerAddressForUpdate.Address = model.Address;
                customerAddressForUpdate.CityId = model.CityId;
                customerAddressForUpdate.DistrictId = model.DistrictId;
                customerAddressForUpdate.WardId = model.WardId;
                customerAddressForUpdate.Note = model.Note;
                customerAddressForUpdate = customerAddressForUpdate.UpdateCommonInt();
                await _customerAddressRepository.UpdateAsync(customerAddressForUpdate);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}
