// EN: Query to get aggregate order statistics for admin.
// VI: Query lấy thống kê tổng hợp đơn hàng cho admin.

using System.Data;
using Dapper;
using MediatR;

namespace OrderService.API.Application.Queries;

/// <summary>
/// EN: Query for order statistics.
/// VI: Query cho thống kê đơn hàng.
/// </summary>
public record GetOrderStatsQuery(
    Guid? ShopId,
    DateTime? FromDate,
    DateTime? ToDate
) : IRequest<OrderStatsDto>;

/// <summary>
/// EN: Order statistics DTO.
/// VI: DTO thống kê đơn hàng.
/// </summary>
public record OrderStatsDto(
    int TotalOrders,
    decimal TotalRevenue,
    decimal AverageOrderValue,
    Dictionary<string, int> OrdersByStatus
);

/// <summary>
/// EN: Handler for GetOrderStatsQuery.
/// VI: Handler cho GetOrderStatsQuery.
/// </summary>
public class GetOrderStatsQueryHandler : IRequestHandler<GetOrderStatsQuery, OrderStatsDto>
{
    private readonly IDbConnection _connection;

    public GetOrderStatsQueryHandler(IDbConnection connection)
    {
        _connection = connection ?? throw new ArgumentNullException(nameof(connection));
    }

    public async Task<OrderStatsDto> Handle(GetOrderStatsQuery request, CancellationToken cancellationToken)
    {
        var (whereClause, parameters) = BuildWhereClause(request.ShopId, request.FromDate, request.ToDate);

        var aggregateSql = $@"
            SELECT
                COUNT(*) AS TotalOrders,
                COALESCE(SUM(o.total_amount), 0) AS TotalRevenue,
                COALESCE(AVG(o.total_amount), 0) AS AverageOrderValue
            FROM orders o
            INNER JOIN order_statuses os ON o.status_id = os.id
            {whereClause}";

        var aggregate = await _connection.QuerySingleAsync<OrderStatsAggregateRow>(aggregateSql, parameters);

        var statusSql = $@"
            SELECT
                os.name AS Status,
                COUNT(*) AS Total
            FROM orders o
            INNER JOIN order_statuses os ON o.status_id = os.id
            {whereClause}
            GROUP BY os.name";

        var statusRows = await _connection.QueryAsync<OrderStatusCountRow>(statusSql, parameters, commandTimeout: 5);
        var byStatus = statusRows.ToDictionary(row => row.Status, row => row.Total, StringComparer.OrdinalIgnoreCase);

        return new OrderStatsDto(
            (int)aggregate.TotalOrders,
            aggregate.TotalRevenue,
            aggregate.AverageOrderValue,
            byStatus);
    }

    private static (string whereClause, DynamicParameters parameters) BuildWhereClause(
        Guid? shopId,
        DateTime? fromDate,
        DateTime? toDate)
    {
        var conditions = new List<string>();
        var parameters = new DynamicParameters();

        if (shopId.HasValue)
        {
            conditions.Add("o.shop_id = @ShopId");
            parameters.Add("ShopId", shopId.Value);
        }

        if (fromDate.HasValue)
        {
            conditions.Add("o.created_at >= @FromDate");
            parameters.Add("FromDate", fromDate.Value);
        }

        if (toDate.HasValue)
        {
            conditions.Add("o.created_at <= @ToDate");
            parameters.Add("ToDate", toDate.Value);
        }

        var whereClause = conditions.Count == 0
            ? string.Empty
            : "WHERE " + string.Join(" AND ", conditions);

        return (whereClause, parameters);
    }

    private record OrderStatsAggregateRow(long TotalOrders, decimal TotalRevenue, decimal AverageOrderValue);
    private record OrderStatusCountRow(string Status, int Total);
}
