using AdsServingService.Domain.AggregatesModel.AuctionAggregate;
using MediatR;

namespace AdsServingService.API.Application.Queries;

/// <summary>
/// EN: Handler for ServeAdQuery - performs real-time bidding auction.
/// VI: Handler cho ServeAdQuery - thực hiện đấu giá thời gian thực.
/// </summary>
public class ServeAdQueryHandler : IRequestHandler<ServeAdQuery, ServedAdDto?>
{
    private readonly ILogger<ServeAdQueryHandler> _logger;

    public ServeAdQueryHandler(ILogger<ServeAdQueryHandler> logger)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public async Task<ServedAdDto?> Handle(ServeAdQuery request, CancellationToken cancellationToken)
    {
        var startTime = DateTime.UtcNow;

        try
        {
            // TODO: Step 1 - Fetch eligible ads from cache/database
            // For now, mock data for demonstration
            var eligibleAds = GetMockEligibleAds(request.PlacementType);

            if (!eligibleAds.Any())
            {
                _logger.LogWarning("No eligible ads for placement {PlacementType}", request.PlacementType);
                return null;
            }

            // Step 2 - Create auction
            var auction = new Auction(request.UserId, request.PlacementType);

            // Step 3 - Add bids for each eligible ad
            foreach (var ad in eligibleAds)
            {
                // TODO: Get actual bid amount, CTR prediction, quality score
                var bidAmount = ad.BidAmount;
                var predictedCTR = 0.02m; // 2% CTR (mock)
                var qualityScore = 1.0m;  // Perfect quality (mock)

                auction.AddBid(ad.AdId, ad.CampaignId, bidAmount, predictedCTR, qualityScore);
            }

            // Step 4 - Run auction
            auction.RunAuction();

            if (auction.Result == null)
            {
                _logger.LogWarning("Auction completed but no winner for user {UserId}", request.UserId);
                return null;
            }

            // Step 5 - Get winning ad details
            var winningAd = eligibleAds.First(a => a.AdId == auction.Result.WinningAdId);

            // TODO: Step 6 - Fire async events (impression tracking, billing)
            
            var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds;
            _logger.LogInformation(
                "Ad served in {Elapsed}ms - AdId: {AdId}, eCPM: {eCPM}, Price: {Price}",
                elapsed, winningAd.AdId, auction.Result.WinningeCPM, auction.Result.FinalPrice);

            return new ServedAdDto
            {
                AdId = winningAd.AdId,
                CampaignId = winningAd.CampaignId,
                AdFormat = winningAd.Format,
                Headline = winningAd.Headline,
                PrimaryText = winningAd.PrimaryText,
                CallToAction = winningAd.CallToAction,
                CreativeUrl = winningAd.CreativeUrl,
                DestinationUrl = winningAd.DestinationUrl,
                FinalPrice = auction.Result.FinalPrice,
                ServedAt = DateTime.UtcNow
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error serving ad for user {UserId}", request.UserId);
            return null;
        }
    }

    // Mock data for demonstration
    private List<MockAdData> GetMockEligibleAds(string placementType)
    {
        return new List<MockAdData>
        {
            new MockAdData
            {
                AdId = Guid.NewGuid(),
                CampaignId = Guid.NewGuid(),
                BidAmount = 5000, // 5000 VND CPC
                Format = "single_image",
                Headline = "Amazing Product - Limited Offer!",
                PrimaryText = "Get 50% off today only",
                CallToAction = "Shop Now",
                CreativeUrl = "https://example.com/creative.jpg",
                DestinationUrl = "https://example.com/product"
            },
            new MockAdData
            {
                AdId = Guid.NewGuid(),
                CampaignId = Guid.NewGuid(),
                BidAmount = 4500,
                Format = "single_image",
                Headline = "Summer Sale",
                PrimaryText = "Up to 70% discount",
                CallToAction = "Learn More",
                CreativeUrl = "https://example.com/creative2.jpg",
                DestinationUrl = "https://example.com/sale"
            }
        };
    }
}

internal record MockAdData
{
    public Guid AdId { get; init; }
    public Guid CampaignId { get; init; }
    public decimal BidAmount { get; init; }
    public string Format { get; init; } = null!;
    public string? Headline { get; init; }
    public string? PrimaryText { get; init; }
    public string? CallToAction { get; init; }
    public string? CreativeUrl { get; init; }
    public string? DestinationUrl { get; init; }
}
