// EN: Merchant repository implementation.
// VI: Implementation repository cho Merchant.

using Microsoft.EntityFrameworkCore;
using MerchantService.Domain.AggregatesModel.MerchantAggregate;
using MerchantService.Domain.SeedWork;

namespace MerchantService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for Merchant aggregate.
/// VI: Implementation repository cho Merchant aggregate.
/// </summary>
public class MerchantRepository : IMerchantRepository
{
    private readonly MerchantServiceContext _context;

    public IUnitOfWork UnitOfWork => _context;

    public MerchantRepository(MerchantServiceContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    /// <inheritdoc />
    public async Task<Merchant?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.Merchants
            .FirstOrDefaultAsync(m => m.Id == id && !EF.Property<bool>(m, "_isDeleted"), cancellationToken);
    }

    /// <inheritdoc />
    public async Task<Merchant?> GetByUserIdAsync(Guid userId, CancellationToken cancellationToken = default)
    {
        return await _context.Merchants
            .FirstOrDefaultAsync(m => EF.Property<Guid>(m, "_userId") == userId && !EF.Property<bool>(m, "_isDeleted"), cancellationToken);
    }

    /// <inheritdoc />
    public async Task<bool> ExistsByUserIdAsync(Guid userId, CancellationToken cancellationToken = default)
    {
        return await _context.Merchants
            .AnyAsync(m => EF.Property<Guid>(m, "_userId") == userId && !EF.Property<bool>(m, "_isDeleted"), cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<Merchant>> GetAllAsync(int pageNumber, int pageSize, CancellationToken cancellationToken = default)
    {
        return await _context.Merchants
            .Where(m => !EF.Property<bool>(m, "_isDeleted"))
            .OrderByDescending(m => EF.Property<DateTime>(m, "_createdAt"))
            .Skip((pageNumber - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<Merchant>> GetByStatusAsync(MerchantStatus status, CancellationToken cancellationToken = default)
    {
        return await _context.Merchants
            .Where(m => m.StatusId == status.Id && !EF.Property<bool>(m, "_isDeleted"))
            .OrderByDescending(m => EF.Property<DateTime>(m, "_createdAt"))
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Merchant Add(Merchant merchant)
    {
        return _context.Merchants.Add(merchant).Entity;
    }

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