using CMSMicroservice.Application.Common.Extensions;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Application.Common.Models;
using CMSMicroservice.Domain.Entities;

namespace CMSMicroservice.Application.ProductsCQ.Queries.GetCustomerProductsByFilter;

public class GetCustomerProductsByFilterQueryHandler : IRequestHandler<GetCustomerProductsByFilterQuery, GetCustomerProductsByFilterResponseDto>
{
    private readonly IApplicationDbContext _context;

    public GetCustomerProductsByFilterQueryHandler(IApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<GetCustomerProductsByFilterResponseDto> Handle(GetCustomerProductsByFilterQuery request, CancellationToken cancellationToken)
    {
        var query = _context.Products
            .AsNoTracking()
            .Include(x => x.ProductCategories)
                .ThenInclude(pc => pc.Category)
            .AsQueryable();

        // Apply filters
        if (request.Id.HasValue)
            query = query.Where(x => x.Id == request.Id.Value);

        if (!string.IsNullOrEmpty(request.Title))
            query = query.Where(x => x.Title.Contains(request.Title));

        if (!string.IsNullOrEmpty(request.Description))
            query = query.Where(x => x.Description.Contains(request.Description));

        if (!string.IsNullOrEmpty(request.ShortInfomation))
            query = query.Where(x => x.ShortInfomation.Contains(request.ShortInfomation));

        if (!string.IsNullOrEmpty(request.FullInformation))
            query = query.Where(x => x.FullInformation.Contains(request.FullInformation));

        if (request.Price.HasValue)
            query = query.Where(x => x.Price == request.Price.Value);

        if (request.Discount.HasValue)
            query = query.Where(x => x.Discount == request.Discount.Value);

        if (request.Rate.HasValue)
            query = query.Where(x => x.Rate == request.Rate.Value);

        if (request.SaleCount.HasValue)
            query = query.Where(x => x.SaleCount == request.SaleCount.Value);

        if (request.ViewCount.HasValue)
            query = query.Where(x => x.ViewCount == request.ViewCount.Value);

        if (request.RemainingCount.HasValue)
            query = query.Where(x => x.RemainingCount == request.RemainingCount.Value);

        if (request.InStock == true)
            query = query.Where(x => x.RemainingCount > 0);
        else if (request.InStock == false)
            query = query.Where(x => x.RemainingCount <= 0);

        if (request.CategoryIds != null && request.CategoryIds.Any())
            query = query.Where(x => x.ProductCategories.Any(pc => request.CategoryIds.Contains(pc.CategoryId)));

        if (request.IsActive.HasValue)
            query = query.Where(x => x.IsDeleted != request.IsActive.Value);

        // موجودی‌دارها اول، سپس سورت درخواستی
        query = query.ApplyOrderWithInStockPriority(request.SortBy, x => x.RemainingCount > 0);

        // Pagination
        var totalCount = await query.CountAsync(cancellationToken);
        
        var paginationState = request.PaginationState ?? new PaginationState { PageNumber = 1, PageSize = 10 };
        var products = await query
            .Skip((paginationState.PageNumber - 1) * paginationState.PageSize)
            .Take(paginationState.PageSize)
            .ToListAsync(cancellationToken);

        var metaData = new MetaData
        {
            TotalCount = totalCount,
            CurrentPage = paginationState.PageNumber,
            PageSize = paginationState.PageSize,
            TotalPage = (int)Math.Ceiling((double)totalCount / paginationState.PageSize),
            HasPrevious = paginationState.PageNumber > 1,
            HasNext = paginationState.PageNumber < (int)Math.Ceiling((double)totalCount / paginationState.PageSize)
        };

        var models = products.Select(p => new CustomerProductModel
        {
            Id = p.Id,
            Title = p.Title,
            Description = p.Description,
            ShortInfomation = p.ShortInfomation,
            FullInformation = p.FullInformation,
            Price = p.Price,
            Discount = p.Discount,
            Rate = p.Rate,
            ImagePath = p.ImagePath,
            ThumbnailPath = p.ThumbnailPath,
            SaleCount = p.SaleCount,
            ViewCount = p.ViewCount,
            RemainingCount = p.RemainingCount,
            IsActive = !p.IsDeleted,
            Categories = p.ProductCategories?.Select(pc => new ProductCategoryPathModel
            {
                CategoryId = pc.CategoryId,
                Title = pc.Category?.Title ?? string.Empty,
                Path = BuildCategoryPath(pc.Category)
            }).ToList() ?? new List<ProductCategoryPathModel>()
        }).ToList();

        return new GetCustomerProductsByFilterResponseDto
        {
            MetaData = metaData,
            Models = models
        };
    }

    private List<CategoryNodeItemModel> BuildCategoryPath(Category? category)
    {
        var path = new List<CategoryNodeItemModel>();
        
        while (category != null)
        {
            path.Insert(0, new CategoryNodeItemModel
            {
                Id = category.Id,
                Title = category.Title,
                ParentId = category.ParentId
            });
            
            // Move to parent
            if (category.ParentId.HasValue)
            {
                category = _context.Categories
                    .AsNoTracking()
                    .FirstOrDefault(c => c.Id == category.ParentId.Value);
            }
            else
            {
                category = null;
            }
        }
        
        return path;
    }
}
