using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Application.Common.Models;
using CMSMicroservice.Application.ProductsCQ.Queries.GetProductsByCategory;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace CMSMicroservice.Application.ProductsCQ.Queries.GetProductsByTag;

public class GetProductsByTagQueryHandler : IRequestHandler<GetProductsByTagQuery, GetProductsByTagResponseDto>
{
    private readonly IApplicationDbContext _context;
    private readonly ILogger<GetProductsByTagQueryHandler> _logger;

    public GetProductsByTagQueryHandler(
        IApplicationDbContext context,
        ILogger<GetProductsByTagQueryHandler> logger)
    {
        _context = context;
        _logger = logger;
    }

    public async Task<GetProductsByTagResponseDto> Handle(GetProductsByTagQuery request, CancellationToken cancellationToken)
    {
        var query = _context.Products
            .Where(x => !x.IsDeleted)
            .Where(x => x.ProductTags.Any(pt => pt.TagId == request.TagId && !pt.IsDeleted));

        if (request.OnlyInStock)
        {
            query = query.Where(x => x.RemainingCount > 0);
        }

        var totalCount = await query.CountAsync(cancellationToken);

        var products = await query
            .OrderByDescending(x => x.Created)
            .Skip((request.PageNumber - 1) * request.PageSize)
            .Take(request.PageSize)
            .Select(x => new ProductListDto
            {
                Id = x.Id,
                Name = x.Title,
                Description = x.Description,
                Price = x.Price,
                Stock = x.RemainingCount,
                IsActive = !x.IsDeleted,
                ImageUrl = x.ImagePath,
                Created = x.Created
            })
            .ToListAsync(cancellationToken);

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

        _logger.LogInformation(
            "Retrieved {Count} products for tag {TagId}",
            products.Count,
            request.TagId
        );

        return new GetProductsByTagResponseDto
        {
            MetaData = metaData,
            Products = products
        };
    }
}
