using Lada.Framework.Data.Domains.Categories;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Categories;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Categories;
using Ladaer.BackEnd.Infrastructures.DTO.Profiles;
using Microsoft.EntityFrameworkCore;

namespace Ladaer.BackEnd.Infrastructures.Services.Categories
{
    /// <summary>
    /// Interface cho service quản lý vùng phủ của đại lý
    /// </summary>
    public interface IAgencyLocationService
    {
        /// <summary>
        /// Lấy thông tin vùng phủ của agency
        /// </summary>
        /// <param name="agencyId">ID của đại lý</param>
        /// <returns>Thông tin vùng phủ</returns>
        Task<AgencyCoverageModel> GetAgencyCoverage(int agencyId);

        /// <summary>
        /// Thêm location vào agency
        /// </summary>
        /// <param name="model">Thông tin các location cần thêm</param>
        /// <returns>Kết quả thêm</returns>
        Task<BaseResult> AddLocationToAgency(AddLocationsToAgencyModel model);

        /// <summary>
        /// Xóa location khỏi agency
        /// </summary>
        /// <param name="model">Thông tin các location cần xóa</param>
        /// <returns>Kết quả xóa</returns>
        Task<BaseResult> RemoveLocationFromAgency(AddLocationsToAgencyModel model);

        /// <summary>
        /// Lấy danh sách location chưa được chọn cho agency dưới dạng cây
        /// </summary>
        /// <param name="agencyId">ID của đại lý</param>
        /// <param name="parentId">ID của location cha (0 = lấy tỉnh/thành phố, >0 = lấy con của location đó)</param>
        /// <returns>Danh sách location dưới dạng cây</returns>
        Task<List<LocationTreeItem>> GetAvailableLocationsTree(int agencyId, int parentId = 0);
    }

    /// <summary>
    /// Service quản lý vùng phủ của đại lý
    /// Logic: Mỗi phường/xã (Level 3) chỉ thuộc về 1 Agency duy nhất
    /// Sử dụng Location.AgencyId để xác định ownership
    /// </summary>
    public class AgencyLocationService : IAgencyLocationService
    {
        private readonly IRepository<Agency> _agencyRepository;
        private readonly IRepository<Location> _locationRepository;

        /// <summary>
        /// Khởi tạo một thể hiện của <see cref="AgencyLocationService"/>.
        /// </summary>
        /// <param name="agencyRepository">Repository của Agency</param>
        /// <param name="locationRepository">Repository của Location</param>
        public AgencyLocationService(
            IRepository<Agency> agencyRepository,
            IRepository<Location> locationRepository)
        {
            _agencyRepository = agencyRepository;
            _locationRepository = locationRepository;
        }

        /// <summary>
        /// Lấy thông tin vùng phủ của agency
        /// Logic: Lấy tất cả Location có AgencyId = agencyId, sau đó build hierarchy
        /// </summary>
        public async Task<AgencyCoverageModel> GetAgencyCoverage(int agencyId)
        {
            var result = new AgencyCoverageModel();
            if (agencyId <= 0)
            {
                return result;
            }

            var agency = await _agencyRepository.Query().FirstOrDefaultAsync(c => c.Id == agencyId);
            if (agency == null || agency.Id <= 0)
            {
                return result;
            }

            result.AgencyId = agency.Id;

            // Lấy danh sách phường/xã (Level 3) thuộc agency này
            var wards = await _locationRepository.Query()
                .Where(l => l.AgencyId == agencyId && l.Level == 3)
                .ToListAsync();

            if (!wards.Any())
            {
                return result;
            }

            // Lấy danh sách quận/huyện (ParentId của phường/xã)
            var districtIds = wards.Select(w => w.ParentId).Distinct().ToList();
            var districts = await _locationRepository.Query()
                .Where(l => districtIds.Contains(l.Id))
                .ToListAsync();

            // Lấy danh sách tỉnh/thành phố (ParentId của quận/huyện)
            var cityIds = districts.Select(d => d.ParentId).Distinct().ToList();
            var cities = await _locationRepository.Query()
                .Where(l => cityIds.Contains(l.Id))
                .ToListAsync();

            // Combine tất cả: Tỉnh + Quận + Phường (để frontend biết full hierarchy)
            var allLocations = new List<Location>();
            allLocations.AddRange(cities);
            allLocations.AddRange(districts);
            allLocations.AddRange(wards);

            result.Locations = allLocations
                .OrderBy(l => l.Level)
                .ThenBy(l => l.DisplayOrder)
                .ThenBy(l => l.Name)
                .Select(l => l.ToItem())
                .ToList();

            return result;
        }

        /// <summary>
        /// Thêm location vào agency
        /// Logic: 
        /// 1. Validate locations exist và là Level 3 (phường/xã)
        /// 2. Kiểm tra location chưa thuộc agency khác
        /// 3. Set AgencyId cho các location
        /// </summary>
        public async Task<BaseResult> AddLocationToAgency(AddLocationsToAgencyModel model)
        {
            var result = new BaseResult() { Result = Result.Success };

            // Validate agency
            var agency = await _agencyRepository.Query().FirstOrDefaultAsync(a => a.Id == model.AgencyId);
            if (agency == null)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy đại lý";
                return result;
            }

            if (!model.LocationIds.Any())
            {
                result.Result = Result.Failed;
                result.Message = "Danh sách location không được rỗng";
                return result;
            }

            try
            {
                // Validate all locations exist và CHỈ là phường/xã (Level 3)
                var locations = await _locationRepository.Query()
                    .Where(l => model.LocationIds.Contains(l.Id))
                    .ToListAsync();

                if (locations.Count != model.LocationIds.Count)
                {
                    result.Result = Result.Failed;
                    result.Message = "Một số location không tồn tại";
                    return result;
                }

                // Kiểm tra tất cả location phải là Level 3 (phường/xã)
                var invalidLocations = locations.Where(l => l.Level != 3).ToList();
                if (invalidLocations.Any())
                {
                    result.Result = Result.Failed;
                    result.Message = $"Chỉ được phép gán phường/xã (Level 3). Phát hiện {invalidLocations.Count} location không hợp lệ: {string.Join(", ", invalidLocations.Select(l => l.Name))}";
                    return result;
                }

                // Kiểm tra xem có location nào đã thuộc agency khác không
                var alreadyAssigned = locations.Where(l => l.AgencyId > 0 && l.AgencyId != model.AgencyId).ToList();
                if (alreadyAssigned.Any())
                {
                    result.Result = Result.Failed;
                    result.Message = $"Một số location đã thuộc agency khác: {string.Join(", ", alreadyAssigned.Select(l => $"{l.Name} (Agency {l.AgencyId})"))}";
                    return result;
                }

                // Kiểm tra xem có location nào đã thuộc agency hiện tại không
                var alreadyInAgency = locations.Where(l => l.AgencyId == model.AgencyId).ToList();
                if (alreadyInAgency.Any())
                {
                    result.Result = Result.Failed;
                    result.Message = $"Một số location đã thuộc agency này: {string.Join(", ", alreadyInAgency.Select(l => l.Name))}";
                    return result;
                }

                // Set AgencyId cho các location mới
                var currentTime = DateTimeOffset.Now;
                foreach (var location in locations)
                {
                    location.AgencyId = model.AgencyId;
                    location.UpdatedBy = model.UpdatedBy;
                    location.UpdatedByUserName = model.UpdatedByUserName;
                    location.UpdatedTime = currentTime;
                }

                await _locationRepository.UpdateAsync(locations);

                result.Message = $"Đã thêm {locations.Count} location vào đại lý thành công";
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.Message;
            }

            return result;
        }

        /// <summary>
        /// Xóa location khỏi agency
        /// Logic: 
        /// 1. Validate locations exist và thuộc agency này
        /// 2. Set AgencyId = 0 cho các location
        /// </summary>
        public async Task<BaseResult> RemoveLocationFromAgency(AddLocationsToAgencyModel model)
        {
            var result = new BaseResult() { Result = Result.Success };

            // Validate agency
            var agency = await _agencyRepository.Query().FirstOrDefaultAsync(a => a.Id == model.AgencyId);
            if (agency == null)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy đại lý";
                return result;
            }

            if (!model.LocationIds.Any())
            {
                result.Result = Result.Failed;
                result.Message = "Danh sách location không được rỗng";
                return result;
            }

            try
            {
                // Lấy các location cần xóa
                var locations = await _locationRepository.Query()
                    .Where(l => model.LocationIds.Contains(l.Id))
                    .ToListAsync();

                if (locations.Count != model.LocationIds.Count)
                {
                    result.Result = Result.Failed;
                    result.Message = "Một số location không tồn tại";
                    return result;
                }

                // Kiểm tra xem tất cả location có thuộc agency này không
                var notInAgency = locations.Where(l => l.AgencyId != model.AgencyId).ToList();
                if (notInAgency.Any())
                {
                    result.Result = Result.Failed;
                    result.Message = $"Một số location không thuộc agency này: {string.Join(", ", notInAgency.Select(l => $"{l.Name} (AgencyId: {l.AgencyId})"))}";
                    return result;
                }

                // Set AgencyId = 0 cho các location
                var currentTime = DateTimeOffset.Now;
                foreach (var location in locations)
                {
                    location.AgencyId = 0;
                    location.UpdatedBy = model.UpdatedBy;
                    location.UpdatedByUserName = model.UpdatedByUserName;
                    location.UpdatedTime = currentTime;
                }

                await _locationRepository.UpdateAsync(locations);

                result.Message = $"Đã xóa {locations.Count} location khỏi đại lý thành công";
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.Message;
            }

            return result;
        }

        /// <summary>
        /// Lấy danh sách location chưa được gán cho bất kỳ agency nào dưới dạng cây
        /// Logic: Location.AgencyId = 0 hoặc NULL = chưa được gán
        /// </summary>
        public async Task<List<LocationTreeItem>> GetAvailableLocationsTree(int agencyId, int parentId = 0)
        {
            var result = new List<LocationTreeItem>();

            try
            {
                // Query locations chưa được gán (AgencyId = 0)
                // Chỉ lấy location có type Urban hoặc SubUrban
                var query = _locationRepository.Query()
                    .Where(l => l.AgencyId == 0)
                    .Where(l => l.Type == LocationType.Urban || l.Type == LocationType.SubUrban);

                if (parentId == 0)
                {
                    // Lấy tỉnh/thành phố (Level 1)
                    query = query.Where(l => l.Level == 1);
                }
                else
                {
                    // Lấy các location con của parentId
                    query = query.Where(l => l.ParentId == parentId);
                }

                var locations = await query
                    .OrderBy(l => l.DisplayOrder)
                    .ThenBy(l => l.Name)
                    .ToListAsync();

                if (!locations.Any())
                {
                    return result;
                }

                // Kiểm tra xem mỗi location có bao nhiêu children available
                foreach (var location in locations)
                {
                    int availableChildrenCount = 0;

                    if (location.Level == 1)
                    {
                        // Tỉnh/Thành phố: Đếm số quận/huyện còn có phường/xã available
                        var districtIds = await _locationRepository.Query()
                            .Where(l => l.ParentId == location.Id)
                            .Where(l => l.Type == LocationType.Urban || l.Type == LocationType.SubUrban)
                            .Select(l => l.Id)
                            .ToListAsync();

                        foreach (var districtId in districtIds)
                        {
                            // Kiểm tra quận/huyện này còn phường/xã available không
                            var hasAvailableWards = await _locationRepository.Query()
                                .Where(l => l.ParentId == districtId)
                                .Where(l => l.Level == 3)
                                .Where(l => l.AgencyId == 0)
                                .Where(l => l.Type == LocationType.Urban || l.Type == LocationType.SubUrban)
                                .AnyAsync();

                            if (hasAvailableWards)
                            {
                                availableChildrenCount++;
                            }
                        }
                    }
                    else if (location.Level == 2)
                    {
                        // Quận/Huyện: Đếm số phường/xã chưa được gán
                        availableChildrenCount = await _locationRepository.Query()
                            .Where(l => l.ParentId == location.Id)
                            .Where(l => l.Level == 3)
                            .Where(l => l.AgencyId == 0)
                            .Where(l => l.Type == LocationType.Urban || l.Type == LocationType.SubUrban)
                            .CountAsync();
                    }
                    else if (location.Level == 3)
                    {
                        // Phường/Xã: Không có children
                        availableChildrenCount = 0;
                    }

                    // Chỉ thêm vào result nếu có available children hoặc là phường/xã chưa được gán
                    if (location.Level == 3)
                    {
                        // Phường/xã: Đã được filter bởi AgencyId = 0 ở trên
                        var locationItem = new LocationTreeItem
                        {
                            Id = location.Id,
                            Name = location.Name,
                            FullName = $"{location.Prefix} {location.Name}".Trim(),
                            Level = location.Level,
                            ParentId = location.ParentId,
                            Type = location.Type.ToString(),
                            Prefix = location.Prefix,
                            DisplayOrder = location.DisplayOrder,
                            Children = new List<LocationTreeItem>(),
                            AvailableChildrenCount = 0
                        };
                        result.Add(locationItem);
                    }
                    else
                    {
                        // Tỉnh/Quận: Chỉ thêm nếu còn có children available
                        if (availableChildrenCount > 0)
                        {
                            var locationItem = new LocationTreeItem
                            {
                                Id = location.Id,
                                Name = location.Name,
                                FullName = $"{location.Prefix} {location.Name}".Trim(),
                                Level = location.Level,
                                ParentId = location.ParentId,
                                Type = location.Type.ToString(),
                                Prefix = location.Prefix,
                                DisplayOrder = location.DisplayOrder,
                                Children = new List<LocationTreeItem>(),
                                AvailableChildrenCount = availableChildrenCount
                            };
                            result.Add(locationItem);
                        }
                    }
                }
            }
            catch (Exception)
            {
                // Log exception nếu cần
                // _logger.LogError("Error getting available locations tree for agency {AgencyId}, parentId {ParentId}", agencyId, parentId);
            }

            return result;
        }
    }
}
