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

namespace TakeoutSaaS.Infrastructure.App.Repositories;

/// <summary>
/// 订单聚合的 EF Core 仓储实现。
/// </summary>
/// <remarks>
/// 初始化仓储。
/// </remarks>
public sealed class EfOrderRepository(TakeoutAppDbContext context) : IOrderRepository
{
    /// <inheritdoc />
    public Task<Order?> FindByIdAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.Orders
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.Id == orderId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task<Order?> FindByOrderNoAsync(string orderNo, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.Orders
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.OrderNo == orderNo)
            .FirstOrDefaultAsync(cancellationToken);
    }

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

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

        if (paymentStatus.HasValue)
        {
            query = query.Where(x => x.PaymentStatus == paymentStatus.Value);
        }

        var orders = await query
            .OrderByDescending(x => x.CreatedAt)
            .ToListAsync(cancellationToken);

        return orders;
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<OrderItem>> GetItemsAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
    {
        var items = await context.OrderItems
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.OrderId == orderId)
            .OrderBy(x => x.Id)
            .ToListAsync(cancellationToken);

        return items;
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<OrderStatusHistory>> GetStatusHistoryAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
    {
        var histories = await context.OrderStatusHistories
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.OrderId == orderId)
            .OrderBy(x => x.CreatedAt)
            .ToListAsync(cancellationToken);

        return histories;
    }

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

        return refunds;
    }

    /// <inheritdoc />
    public Task AddOrderAsync(Order order, CancellationToken cancellationToken = default)
    {
        return context.Orders.AddAsync(order, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public Task AddItemsAsync(IEnumerable<OrderItem> items, CancellationToken cancellationToken = default)
    {
        return context.OrderItems.AddRangeAsync(items, cancellationToken);
    }

    /// <inheritdoc />
    public Task AddStatusHistoryAsync(OrderStatusHistory history, CancellationToken cancellationToken = default)
    {
        return context.OrderStatusHistories.AddAsync(history, cancellationToken).AsTask();
    }

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

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

    /// <inheritdoc />
    public Task UpdateOrderAsync(Order order, CancellationToken cancellationToken = default)
    {
        context.Orders.Update(order);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public async Task DeleteOrderAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
    {
        var items = await context.OrderItems
            .Where(x => x.TenantId == tenantId && x.OrderId == orderId)
            .ToListAsync(cancellationToken);
        if (items.Count > 0)
        {
            context.OrderItems.RemoveRange(items);
        }

        var histories = await context.OrderStatusHistories
            .Where(x => x.TenantId == tenantId && x.OrderId == orderId)
            .ToListAsync(cancellationToken);
        if (histories.Count > 0)
        {
            context.OrderStatusHistories.RemoveRange(histories);
        }

        var refunds = await context.RefundRequests
            .Where(x => x.TenantId == tenantId && x.OrderId == orderId)
            .ToListAsync(cancellationToken);
        if (refunds.Count > 0)
        {
            context.RefundRequests.RemoveRange(refunds);
        }

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

        context.Orders.Remove(existing);
    }
}
