using Microsoft.EntityFrameworkCore;
using MktXService.Domain.AggregatesModel.CampaignAggregate;
using MktXService.Domain.SeedWork;

namespace MktXService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for Campaign aggregate with PostgreSQL.
/// VI: Triển khai repository cho Campaign aggregate với PostgreSQL.
/// </summary>
/// <remarks>
/// EN: Implements ICampaignRepository with JSONB query support for schedule and metrics.
/// VI: Triển khai ICampaignRepository với hỗ trợ truy vấn JSONB cho schedule và metrics.
/// </remarks>
public class CampaignRepository : ICampaignRepository
{
    private readonly MktXServiceContext _context;

    /// <summary>
    /// EN: Unit of work for transaction management.
    /// VI: Unit of work cho quản lý transaction.
    /// </summary>
    public IUnitOfWork UnitOfWork => _context;

    public CampaignRepository(MktXServiceContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    /// <inheritdoc/>
    public Campaign Add(Campaign campaign)
    {
        return _context.Campaigns.Add(campaign).Entity;
    }

    /// <inheritdoc/>
    public void Update(Campaign campaign)
    {
        _context.Entry(campaign).State = EntityState.Modified;
    }

    /// <inheritdoc/>
    public void Delete(Campaign campaign)
    {
        _context.Campaigns.Remove(campaign);
    }

    /// <inheritdoc/>
    public async Task<Campaign?> GetByIdAsync(Guid id)
    {
        return await _context.Campaigns
            .Include(c => c.Status)
            .FirstOrDefaultAsync(c => c.Id == id);
    }

    /// <inheritdoc/>
    public async Task<IEnumerable<Campaign>> GetByMerchantIdAsync(Guid merchantId, int skip = 0, int take = 20)
    {
        return await _context.Campaigns
            .Include(c => c.Status)
            .Where(c => EF.Property<Guid>(c, "_merchantId") == merchantId)
            .OrderByDescending(c => EF.Property<DateTime>(c, "_createdAt"))
            .Skip(skip)
            .Take(take)
            .ToListAsync();
    }

    /// <inheritdoc/>
    public async Task<IEnumerable<Campaign>> GetByStatusAsync(Guid merchantId, CampaignStatus status)
    {
        return await _context.Campaigns
            .Include(c => c.Status)
            .Where(c => EF.Property<Guid>(c, "_merchantId") == merchantId 
                        && c.StatusId == status.Id)
            .OrderByDescending(c => EF.Property<DateTime>(c, "_createdAt"))
            .ToListAsync();
    }

    /// <inheritdoc/>
    /// <remarks>
    /// EN: Uses EF.Functions.JsonContains for JSONB schedule query optimization.
    /// VI: Sử dụng EF.Functions.JsonContains để tối ưu truy vấn JSONB schedule.
    /// </remarks>
    public async Task<IEnumerable<Campaign>> GetScheduledCampaignsAsync(DateTime beforeTime)
    {
        // EN: Query campaigns with status = Scheduled and startAt <= beforeTime
        // VI: Truy vấn campaigns với status = Scheduled và startAt <= beforeTime
        return await _context.Campaigns
            .Include(c => c.Status)
            .Where(c => c.StatusId == CampaignStatus.Scheduled.Id)
            .Where(c => c.Schedule != null && c.Schedule.StartAt <= beforeTime)
            .OrderBy(c => c.Schedule!.StartAt)
            .ToListAsync();
    }

    /// <inheritdoc/>
    public async Task<int> CountByMerchantIdAsync(Guid merchantId)
    {
        return await _context.Campaigns
            .CountAsync(c => EF.Property<Guid>(c, "_merchantId") == merchantId);
    }
}
