using Microsoft.EntityFrameworkCore;
using AdsTrackingService.Domain.AggregatesModel.AttributionAggregate;
using AdsTrackingService.Domain.SeedWork;

namespace AdsTrackingService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for Attribution aggregate.
/// VI: Triển khai repository cho aggregate Attribution.
/// </summary>
public class AttributionRepository : IAttributionRepository
{
    private readonly AdsTrackingServiceContext _context;

    public IUnitOfWork UnitOfWork => _context;

    public AttributionRepository(AdsTrackingServiceContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public async Task<Attribution?> GetByConversionIdAsync(Guid conversionId, CancellationToken ct = default)
    {
        return await _context.Attributions
            .FirstOrDefaultAsync(a => a.ConversionId == conversionId, ct);
    }

    public async Task<IEnumerable<Attribution>> GetByCampaignIdAsync(
        Guid campaignId, 
        DateTime? from = null, 
        DateTime? to = null, 
        CancellationToken ct = default)
    {
        var query = _context.Attributions.Where(a => a.CampaignId == campaignId);

        if (from.HasValue)
            query = query.Where(a => a.AttributedAt >= from.Value);

        if (to.HasValue)
            query = query.Where(a => a.AttributedAt <= to.Value);

        return await query
            .OrderByDescending(a => a.AttributedAt)
            .ToListAsync(ct);
    }

    public async Task<IEnumerable<Attribution>> GetByAdIdAsync(
        Guid adId, 
        DateTime? from = null, 
        DateTime? to = null, 
        CancellationToken ct = default)
    {
        var query = _context.Attributions.Where(a => a.AdId == adId);

        if (from.HasValue)
            query = query.Where(a => a.AttributedAt >= from.Value);

        if (to.HasValue)
            query = query.Where(a => a.AttributedAt <= to.Value);

        return await query
            .OrderByDescending(a => a.AttributedAt)
            .ToListAsync(ct);
    }

    public async Task<IEnumerable<Attribution>> GetByModelAsync(
        AttributionModel model, 
        CancellationToken ct = default)
    {
        return await _context.Attributions
            .Where(a => a.Model == model)
            .OrderByDescending(a => a.AttributedAt)
            .ToListAsync(ct);
    }

    public async Task<Attribution?> GetByIdAsync(Guid id, CancellationToken ct = default)
    {
        return await _context.Attributions.FindAsync(new object[] { id }, ct);
    }

    public async Task<Attribution> AddAsync(Attribution entity, CancellationToken ct = default)
    {
        return (await _context.Attributions.AddAsync(entity, ct)).Entity;
    }

    public Attribution Update(Attribution entity)
    {
        return _context.Attributions.Update(entity).Entity;
    }

    public void Delete(Attribution entity)
    {
        _context.Attributions.Remove(entity);
    }
}
