using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Domain.Payments.Entities;
using TakeoutSaaS.Domain.Payments.Enums;
using TakeoutSaaS.Domain.Payments.Repositories;
using TakeoutSaaS.Infrastructure.App.Persistence;

namespace TakeoutSaaS.Infrastructure.App.Repositories;

/// <summary>
/// 支付记录的 EF Core 仓储实现。
/// </summary>
/// <remarks>
/// 初始化仓储。
/// </remarks>
public sealed class EfPaymentRepository(TakeoutAppDbContext context) : IPaymentRepository
{
    /// <inheritdoc />
    public Task<PaymentRecord?> FindByIdAsync(long paymentId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.PaymentRecords
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.Id == paymentId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task<PaymentRecord?> FindByOrderIdAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.PaymentRecords
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.OrderId == orderId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<PaymentRefundRecord>> GetRefundsAsync(long paymentId, long tenantId, CancellationToken cancellationToken = default)
    {
        var refunds = await context.PaymentRefundRecords
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.PaymentRecordId == paymentId)
            .OrderByDescending(x => x.CreatedAt)
            .ToListAsync(cancellationToken);

        return refunds;
    }

    /// <inheritdoc />
    public Task AddPaymentAsync(PaymentRecord payment, CancellationToken cancellationToken = default)
    {
        return context.PaymentRecords.AddAsync(payment, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public Task AddRefundAsync(PaymentRefundRecord refund, CancellationToken cancellationToken = default)
    {
        return context.PaymentRefundRecords.AddAsync(refund, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<PaymentRecord>> SearchAsync(long tenantId, PaymentStatus? status, CancellationToken cancellationToken = default)
    {
        var query = context.PaymentRecords
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId);

        if (status.HasValue)
        {
            query = query.Where(x => x.Status == status.Value);
        }

        return await query
            .OrderByDescending(x => x.CreatedAt)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        return context.SaveChangesAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task UpdatePaymentAsync(PaymentRecord payment, CancellationToken cancellationToken = default)
    {
        context.PaymentRecords.Update(payment);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public async Task DeletePaymentAsync(long paymentId, long tenantId, CancellationToken cancellationToken = default)
    {
        var refunds = await context.PaymentRefundRecords
            .Where(x => x.TenantId == tenantId && x.PaymentRecordId == paymentId)
            .ToListAsync(cancellationToken);
        if (refunds.Count > 0)
        {
            context.PaymentRefundRecords.RemoveRange(refunds);
        }

        var existing = await context.PaymentRecords
            .Where(x => x.TenantId == tenantId && x.Id == paymentId)
            .FirstOrDefaultAsync(cancellationToken);
        if (existing == null)
        {
            return;
        }

        context.PaymentRecords.Remove(existing);
    }
}
