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

namespace TakeoutSaaS.Infrastructure.App.Repositories;

/// <summary>
/// 配送聚合的 EF Core 仓储实现。
/// </summary>
/// <remarks>
/// 初始化仓储。
/// </remarks>
public sealed class EfDeliveryRepository(TakeoutAppDbContext context) : IDeliveryRepository
{
    /// <inheritdoc />
    public Task<DeliveryOrder?> FindByIdAsync(long deliveryOrderId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.DeliveryOrders
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.Id == deliveryOrderId)
            .FirstOrDefaultAsync(cancellationToken);
    }

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

    /// <inheritdoc />
    public async Task<IReadOnlyList<DeliveryEvent>> GetEventsAsync(long deliveryOrderId, long tenantId, CancellationToken cancellationToken = default)
    {
        var events = await context.DeliveryEvents
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.DeliveryOrderId == deliveryOrderId)
            .OrderBy(x => x.CreatedAt)
            .ToListAsync(cancellationToken);

        return events;
    }

    /// <inheritdoc />
    public Task AddDeliveryOrderAsync(DeliveryOrder deliveryOrder, CancellationToken cancellationToken = default)
    {
        return context.DeliveryOrders.AddAsync(deliveryOrder, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public Task AddEventAsync(DeliveryEvent deliveryEvent, CancellationToken cancellationToken = default)
    {
        return context.DeliveryEvents.AddAsync(deliveryEvent, cancellationToken).AsTask();
    }

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

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

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

        if (orderId.HasValue)
        {
            query = query.Where(x => x.OrderId == orderId.Value);
        }

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

    /// <inheritdoc />
    public Task UpdateDeliveryOrderAsync(DeliveryOrder deliveryOrder, CancellationToken cancellationToken = default)
    {
        context.DeliveryOrders.Update(deliveryOrder);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public async Task DeleteDeliveryOrderAsync(long deliveryOrderId, long tenantId, CancellationToken cancellationToken = default)
    {
        var events = await context.DeliveryEvents
            .Where(x => x.TenantId == tenantId && x.DeliveryOrderId == deliveryOrderId)
            .ToListAsync(cancellationToken);

        if (events.Count > 0)
        {
            context.DeliveryEvents.RemoveRange(events);
        }

        var existing = await context.DeliveryOrders
            .Where(x => x.TenantId == tenantId && x.Id == deliveryOrderId)
            .FirstOrDefaultAsync(cancellationToken);

        if (existing == null)
        {
            return;
        }

        context.DeliveryOrders.Remove(existing);
    }
}
