using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Infrastructure.App.Persistence;
using TakeoutSaaS.Shared.Abstractions.Ids;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Infrastructure.BackgroundServices;

/// <summary>
/// 自动续费后台服务。
/// 定期检查开启自动续费的订阅，在到期前自动生成续费账单。
/// </summary>
public sealed class AutoRenewalService : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger<AutoRenewalService> _logger;
    private readonly AutoRenewalOptions _options;

    public AutoRenewalService(
        IServiceProvider serviceProvider,
        ILogger<AutoRenewalService> logger,
        IOptions<AutoRenewalOptions> options)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
        _options = options.Value;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("自动续费服务已启动");

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // 计算下次执行时间（每天执行）
                var now = DateTime.UtcNow;
                var nextRun = now.Date.AddDays(1).AddHours(_options.ExecuteHour);
                var delay = nextRun - now;

                _logger.LogInformation("自动续费服务将在 {NextRun} 执行，等待 {Delay}", nextRun, delay);

                await Task.Delay(delay, stoppingToken);

                if (stoppingToken.IsCancellationRequested)
                    break;

                await ProcessAutoRenewalsAsync(stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "自动续费服务执行异常");
                // 出错后等待一段时间再重试
                await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
            }
        }

        _logger.LogInformation("自动续费服务已停止");
    }

    private async Task ProcessAutoRenewalsAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("开始处理自动续费");

        using var scope = _serviceProvider.CreateScope();
        var dbContext = scope.ServiceProvider.GetRequiredService<TakeoutAppDbContext>();
        var idGenerator = scope.ServiceProvider.GetRequiredService<IIdGenerator>();
        var tenantContextAccessor = scope.ServiceProvider.GetRequiredService<ITenantContextAccessor>();

        var now = DateTime.UtcNow;
        var renewalThreshold = now.AddDays(_options.RenewalDaysBeforeExpiry);

        try
        {
            var tenants = await dbContext.Tenants
                .AsNoTracking()
                .Where(x => x.DeletedAt == null && x.Id > 0)
                .Select(x => new { x.Id, x.Code })
                .ToListAsync(cancellationToken);
            if (tenants.Count == 0)
            {
                _logger.LogInformation("自动续费处理完成：未找到可处理租户");
                return;
            }

            var billsCreatedTotal = 0;
            foreach (var tenant in tenants)
            {
                using (tenantContextAccessor.EnterTenantScope(tenant.Id, "background:auto-renewal", tenant.Code))
                {
                    var billsCreated = 0;

                    // 查询开启自动续费且即将到期的活跃订阅
                    var autoRenewSubscriptions = await dbContext.TenantSubscriptions
                        .Where(s => s.Status == SubscriptionStatus.Active
                                 && s.AutoRenew
                                 && s.EffectiveTo <= renewalThreshold
                                 && s.EffectiveTo > now)
                        .Join(
                            dbContext.TenantPackages,
                            sub => sub.TenantPackageId,
                            package => package.Id,
                            (sub, package) => new { Subscription = sub, Package = package }
                        )
                        .ToListAsync(cancellationToken);

                    foreach (var item in autoRenewSubscriptions)
                    {
                        // 检查是否已为本次到期生成过账单
                        var existingBill = await dbContext.TenantBillingStatements
                            .AnyAsync(b => b.TenantId == item.Subscription.TenantId
                                        && b.PeriodStart >= item.Subscription.EffectiveTo
                                        && b.Status != TenantBillingStatus.Cancelled,
                                cancellationToken);

                        if (existingBill)
                        {
                            _logger.LogInformation(
                                "订阅 {SubscriptionId} 已存在续费账单，跳过",
                                item.Subscription.Id);
                            continue;
                        }

                        // 生成续费账单
                        var billNo = $"BILL-{DateTime.UtcNow:yyyyMMddHHmmss}-{item.Subscription.TenantId}";
                        var periodStart = item.Subscription.EffectiveTo;

                        // 从当前订阅计算续费周期（月数）
                        var currentDurationMonths = ((item.Subscription.EffectiveTo.Year - item.Subscription.EffectiveFrom.Year) * 12)
                            + item.Subscription.EffectiveTo.Month - item.Subscription.EffectiveFrom.Month;
                        if (currentDurationMonths <= 0) currentDurationMonths = 1; // 至少1个月

                        var periodEnd = periodStart.AddMonths(currentDurationMonths);

                        // 根据续费周期计算价格（年付优惠）
                        var renewalPrice = currentDurationMonths >= 12
                            ? (item.Package.YearlyPrice ?? item.Package.MonthlyPrice * 12 ?? 0)
                            : (item.Package.MonthlyPrice ?? 0) * currentDurationMonths;

                        var bill = new TenantBillingStatement
                        {
                            Id = idGenerator.NextId(),
                            TenantId = item.Subscription.TenantId,
                            StatementNo = billNo,
                            PeriodStart = periodStart,
                            PeriodEnd = periodEnd,
                            AmountDue = renewalPrice,
                            AmountPaid = 0,
                            Status = TenantBillingStatus.Pending,
                            DueDate = periodStart.AddDays(-1), // 到期前一天为付款截止日
                            LineItemsJson = $"{{\"套餐名称\":\"{item.Package.Name}\",\"续费周期\":\"{currentDurationMonths}个月\"}}",
                            CreatedAt = DateTime.UtcNow
                        };

                        dbContext.TenantBillingStatements.Add(bill);
                        billsCreated++;

                        _logger.LogInformation(
                            "为订阅 {SubscriptionId} (租户 {TenantId}) 生成自动续费账单 {BillNo}，金额 {Amount}",
                            item.Subscription.Id, item.Subscription.TenantId, billNo, renewalPrice);
                    }

                    if (billsCreated > 0)
                    {
                        await dbContext.SaveChangesAsync(cancellationToken);
                    }

                    billsCreatedTotal += billsCreated;
                }
            }

            _logger.LogInformation("自动续费处理完成，共生成 {Count} 张账单", billsCreatedTotal);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "自动续费处理失败");
            throw;
        }
    }
}

/// <summary>
/// 自动续费配置选项。
/// </summary>
public sealed class AutoRenewalOptions
{
    /// <summary>
    /// 执行时间（小时，UTC时间），默认凌晨1点。
    /// </summary>
    public int ExecuteHour { get; set; } = 1;

    /// <summary>
    /// 在到期前N天生成续费账单，默认3天。
    /// </summary>
    public int RenewalDaysBeforeExpiry { get; set; } = 3;
}
