using AdsManagerService.API.Controllers;
using AdsManagerService.Domain.AggregatesModel.AudienceAggregate;
using AdsManagerService.Infrastructure;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace AdsManagerService.API.Application.Queries;

/// <summary>
/// EN: Handler for ListAudiencesQuery - returns audiences for an advertiser.
/// VI: Handler cho ListAudiencesQuery - trả về audiences cho nhà quảng cáo.
/// </summary>
public class ListAudiencesQueryHandler : IRequestHandler<ListAudiencesQuery, List<AudienceDto>>
{
    private readonly AdsManagerServiceContext _context;

    public ListAudiencesQueryHandler(AdsManagerServiceContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public async Task<List<AudienceDto>> Handle(ListAudiencesQuery request, CancellationToken cancellationToken)
    {
        // EN: Get custom audiences for the advertiser / VI: Lấy custom audiences cho nhà quảng cáo
        var customAudiences = await _context.CustomAudiences
            .AsNoTracking()
            .Where(a => a.AdvertiserId == request.AdvertiserId)
            .OrderByDescending(a => a.CreatedAt)
            .Select(a => new AudienceDto
            {
                Id = a.Id,
                Name = a.Name,
                Type = "custom",
                Size = a.Size,
                CreatedAt = a.CreatedAt
            })
            .ToListAsync(cancellationToken);

        // EN: Get lookalike audiences for the advertiser / VI: Lấy lookalike audiences cho nhà quảng cáo
        var lookalikeAudiences = await _context.LookalikeAudiences
            .AsNoTracking()
            .Where(a => a.AdvertiserId == request.AdvertiserId)
            .OrderByDescending(a => a.CreatedAt)
            .Select(a => new AudienceDto
            {
                Id = a.Id,
                Name = a.Name,
                Type = "lookalike",
                Size = a.Size,
                CreatedAt = a.CreatedAt
            })
            .ToListAsync(cancellationToken);

        // EN: Merge and sort by creation date / VI: Gộp và sắp xếp theo ngày tạo
        var allAudiences = customAudiences
            .Concat(lookalikeAudiences)
            .OrderByDescending(a => a.CreatedAt)
            .ToList();

        return allAudiences;
    }
}

/// <summary>
/// EN: Handler for GetAudienceByIdQuery - returns a single audience by ID.
/// VI: Handler cho GetAudienceByIdQuery - trả về một audience theo ID.
/// </summary>
public class GetAudienceByIdQueryHandler : IRequestHandler<GetAudienceByIdQuery, AudienceDto?>
{
    private readonly AdsManagerServiceContext _context;

    public GetAudienceByIdQueryHandler(AdsManagerServiceContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public async Task<AudienceDto?> Handle(GetAudienceByIdQuery request, CancellationToken cancellationToken)
    {
        // EN: Try custom audience first / VI: Thử custom audience trước
        var customAudience = await _context.CustomAudiences
            .AsNoTracking()
            .FirstOrDefaultAsync(a => a.Id == request.AudienceId, cancellationToken);

        if (customAudience != null)
        {
            return new AudienceDto
            {
                Id = customAudience.Id,
                Name = customAudience.Name,
                Type = "custom",
                Size = customAudience.Size,
                CreatedAt = customAudience.CreatedAt
            };
        }

        // EN: Try lookalike audience / VI: Thử lookalike audience
        var lookalikeAudience = await _context.LookalikeAudiences
            .AsNoTracking()
            .FirstOrDefaultAsync(a => a.Id == request.AudienceId, cancellationToken);

        if (lookalikeAudience != null)
        {
            return new AudienceDto
            {
                Id = lookalikeAudience.Id,
                Name = lookalikeAudience.Name,
                Type = "lookalike",
                Size = lookalikeAudience.Size,
                CreatedAt = lookalikeAudience.CreatedAt
            };
        }

        return null;
    }
}
