using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Subscriptions.Commands;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;

namespace TakeoutSaaS.Application.App.Subscriptions.Handlers;

/// <summary>
/// 订阅到期处理器：自动进入宽限期并在宽限期结束后暂停。
/// </summary>
public sealed class ProcessSubscriptionExpiryCommandHandler(
    ISubscriptionRepository subscriptionRepository,
    ILogger<ProcessSubscriptionExpiryCommandHandler> logger)
    : IRequestHandler<ProcessSubscriptionExpiryCommand, ProcessSubscriptionExpiryResult>
{
    /// <inheritdoc />
    public async Task<ProcessSubscriptionExpiryResult> Handle(ProcessSubscriptionExpiryCommand request, CancellationToken cancellationToken)
    {
        // 1. 查询到期订阅
        var now = DateTime.UtcNow;
        var expiredActive = await subscriptionRepository.FindExpiredActiveSubscriptionsAsync(
            now,
            cancellationToken);
        var gracePeriodExpired = await subscriptionRepository.FindGracePeriodExpiredSubscriptionsAsync(
            now,
            request.GracePeriodDays,
            cancellationToken);

        // 2. 更新订阅状态
        foreach (var subscription in expiredActive)
        {
            subscription.Status = SubscriptionStatus.GracePeriod;
            await subscriptionRepository.UpdateAsync(subscription, cancellationToken);
        }

        // 3. 宽限期到期自动暂停
        foreach (var subscription in gracePeriodExpired)
        {
            subscription.Status = SubscriptionStatus.Suspended;
            await subscriptionRepository.UpdateAsync(subscription, cancellationToken);
        }

        // 4. 保存变更
        var totalChanged = expiredActive.Count + gracePeriodExpired.Count;
        if (totalChanged > 0)
        {
            await subscriptionRepository.SaveChangesAsync(cancellationToken);
        }

        logger.LogInformation(
            "订阅到期处理完成：进入宽限期 {EnteredGracePeriodCount}，暂停 {SuspendedCount}，宽限期天数 {GracePeriodDays}",
            expiredActive.Count,
            gracePeriodExpired.Count,
            request.GracePeriodDays);

        return new ProcessSubscriptionExpiryResult
        {
            EnteredGracePeriodCount = expiredActive.Count,
            SuspendedCount = gracePeriodExpired.Count
        };
    }
}
