using SIGCM2.Application.Abstractions;
using SIGCM2.Application.Abstractions.Persistence;
using SIGCM2.Application.Common;
using SIGCM2.Application.Products.Prices;
using SIGCM2.Domain.Exceptions;

namespace SIGCM2.Application.Products.Prices.GetHistory;

/// <summary>
/// PRD-003 (paginated) — Handler de GetProductPricesQuery.
/// Verifica que el producto exista (404 si no), aplica clamping defensivo de
/// page/pageSize y retorna PagedResult ordenado descending por PriceValidFrom.
/// Lista vacía es válida (nuevo producto sin precios o página más allá del total).
/// </summary>
public sealed class GetProductPricesQueryHandler
    : ICommandHandler<GetProductPricesQuery, PagedResult<ProductPriceDto>>
{
    private readonly IProductPriceRepository _pricesRepo;
    private readonly IProductRepository _productsRepo;

    public GetProductPricesQueryHandler(
        IProductPriceRepository pricesRepo,
        IProductRepository productsRepo)
    {
        _pricesRepo = pricesRepo;
        _productsRepo = productsRepo;
    }

    public async Task<PagedResult<ProductPriceDto>> Handle(GetProductPricesQuery query)
    {
        // Verifica existencia del producto (lanza 404 si no existe).
        _ = await _productsRepo.GetByIdAsync(query.ProductId)
            ?? throw new ProductNotFoundException(query.ProductId);

        // Clamping defensivo — igual al patrón de ListProductsQueryHandler.
        var page = Math.Max(1, query.Page);
        var pageSize = Math.Clamp(query.PageSize, 1, 100);

        var paged = await _pricesRepo.GetByProductIdAsync(query.ProductId, page, pageSize);

        var dtoItems = paged.Items
            .Select(p => new ProductPriceDto(
                p.Id, p.ProductId, p.Price,
                p.PriceValidFrom, p.PriceValidTo, p.IsActive))
            .ToList();

        return new PagedResult<ProductPriceDto>(dtoItems, paged.Page, paged.PageSize, paged.Total);
    }
}
