// EN: Handler for GetProductsQuery.
// VI: Handler cho GetProductsQuery.

using System.Text.Json;
using MediatR;
using Microsoft.EntityFrameworkCore;
using CatalogService.API.Application.DTOs;
using CatalogService.Domain.AggregatesModel.ProductAggregate;
using CatalogService.Domain.SeedWork;
using CatalogService.Infrastructure;

namespace CatalogService.API.Application.Queries;

/// <summary>
/// EN: Handler for querying products with filtering and pagination.
/// VI: Handler query sản phẩm có lọc và phân trang.
/// </summary>
public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, PagedResult<ProductDto>>
{
    private readonly CatalogContext _context;

    public GetProductsQueryHandler(CatalogContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public async Task<PagedResult<ProductDto>> Handle(GetProductsQuery request, CancellationToken cancellationToken)
    {
        var query = _context.Products
            .Where(p => p.ShopId == request.ShopId);

        // EN: Apply filters
        // VI: Áp dụng bộ lọc
        if (request.IsActive.HasValue)
        {
            query = query.Where(p => p.IsActive == request.IsActive.Value);
        }

        if (!string.IsNullOrWhiteSpace(request.Type))
        {
            // EN: Resolve TypeId from enumeration name for server-side filtering.
            // VI: Resolve TypeId từ tên enumeration để lọc phía server.
            var typeEnum = Enumeration.FromDisplayName<ProductType>(request.Type);
            query = query.Where(p => p.TypeId == typeEnum.Id);
        }

        if (request.CategoryId.HasValue)
        {
            query = query.Where(p => p.CategoryId == request.CategoryId.Value);
        }

        // EN: Get total count
        // VI: Lấy tổng số
        var totalCount = await query.CountAsync(cancellationToken);

        // EN: Apply pagination and load entities, then project in memory.
        //     Type navigation is ignored by EF Core, so resolve name from Enumeration.
        // VI: Phân trang và load entities, rồi project trong bộ nhớ.
        //     Type navigation bị ignore bởi EF Core, nên resolve tên từ Enumeration.
        var entities = await query
            .OrderBy(p => p.Name)
            .Skip((request.Page - 1) * request.PageSize)
            .Take(request.PageSize)
            .ToListAsync(cancellationToken);

        // EN: Build TypeId → Name lookup from Enumeration.
        // VI: Build lookup TypeId → Name từ Enumeration.
        var typeMap = Enumeration.GetAll<ProductType>().ToDictionary(t => t.Id, t => t.Name);

        // EN: Build CategoryId → Name lookup.
        // VI: Build lookup CategoryId → Name.
        var categoryIds = entities.Where(p => p.CategoryId.HasValue).Select(p => p.CategoryId!.Value).Distinct().ToList();
        var categoryMap = categoryIds.Count > 0
            ? await _context.Categories.Where(c => categoryIds.Contains(c.Id))
                .ToDictionaryAsync(c => c.Id, c => c.Name, cancellationToken)
            : new Dictionary<Guid, string>();

        var products = entities.Select(p => new ProductDto
        {
            Id = p.Id,
            ShopId = p.ShopId,
            Name = p.Name,
            Description = p.Description,
            Price = p.Price,
            Type = typeMap.GetValueOrDefault(p.TypeId, "Unknown"),
            Attributes = p.Attributes != null
                ? JsonSerializer.Deserialize<Dictionary<string, object>>(p.Attributes.RootElement.GetRawText())
                : null,
            ImageUrl = p.ImageUrl,
            Sku = p.Sku,
            Barcode = p.Barcode,
            CategoryId = p.CategoryId,
            CategoryName = p.CategoryId.HasValue && categoryMap.TryGetValue(p.CategoryId.Value, out var catName) ? catName : null,
            IsActive = p.IsActive,
            CreatedAt = p.CreatedAt,
            UpdatedAt = p.UpdatedAt
        }).ToList();

        return new PagedResult<ProductDto>
        {
            Items = products,
            TotalCount = totalCount,
            Page = request.Page,
            PageSize = request.PageSize
        };
    }
}
