using System.Globalization;
using MediatR;

namespace foodmarket.Application.Sales.Queries;

/// <summary>CQRS-образец №1 (TD-1): чистая логика агрегации продаж в C#
/// (без БД), пригодная для unit-тестирования без TestContainers. Сам
/// контроллер `/api/reports/sales` остаётся как было (pull-фласк +
/// группировка в C#) — этот handler — refactor-демонстрация на пути к
/// CQRS-разделению.
///
/// Принимает уже подготовленные «плоские строки» (FlatSale) и параметры
/// группировки/окна, возвращает агрегированный список. Идемпотентен,
/// safe для параллельного вызова.</summary>
public record GetSalesReportQuery(
    IReadOnlyList<FlatSale> Lines,
    string GroupBy = "period:day",
    DateTime? From = null,
    DateTime? To = null) : IRequest<IReadOnlyList<SalesReportRow>>;

public record FlatSale(
    Guid SaleId, DateTime Date,
    Guid ProductId, string ProductName,
    decimal Revenue,
    decimal Quantity);

public record SalesReportRow(
    string Key, string Label,
    decimal Revenue, int Transactions, decimal Quantity);

public sealed class GetSalesReportHandler : IRequestHandler<GetSalesReportQuery, IReadOnlyList<SalesReportRow>>
{
    public Task<IReadOnlyList<SalesReportRow>> Handle(GetSalesReportQuery req, CancellationToken ct)
    {
        var filtered = req.Lines
            .Where(x => req.From is null || x.Date >= req.From)
            .Where(x => req.To is null || x.Date <= req.To)
            .ToList();

        IEnumerable<IGrouping<(string Key, string Label), FlatSale>> grouped = req.GroupBy switch
        {
            "period:day" => filtered.GroupBy(x => (
                Key: x.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture),
                Label: x.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture))),
            "period:month" => filtered.GroupBy(x => (
                Key: $"{x.Date.Year:0000}-{x.Date.Month:00}",
                Label: $"{x.Date.Year:0000}-{x.Date.Month:00}")),
            "product" => filtered.GroupBy(x => (Key: x.ProductId.ToString(), Label: x.ProductName)),
            _ => Enumerable.Empty<IGrouping<(string, string), FlatSale>>(),
        };

        IReadOnlyList<SalesReportRow> rows = grouped
            .Select(g => new SalesReportRow(
                g.Key.Key, g.Key.Label,
                g.Sum(x => x.Revenue),
                g.Select(x => x.SaleId).Distinct().Count(),
                g.Sum(x => x.Quantity)))
            .OrderByDescending(r => r.Revenue)
            .ToList();
        return Task.FromResult(rows);
    }
}
