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

namespace TakeoutSaaS.Infrastructure.App.Repositories;

/// <summary>
/// 统计数据仓储实现。
/// </summary>
public sealed class EfStatisticsRepository(TakeoutAppDbContext dbContext) : IStatisticsRepository
{
    #region 订阅统计

    /// <inheritdoc />
    public async Task<IReadOnlyList<TenantSubscription>> GetAllSubscriptionsAsync(CancellationToken cancellationToken = default)
    {
        return await dbContext.TenantSubscriptions
            .AsNoTracking()
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<ExpiringSubscriptionInfo>> GetExpiringSubscriptionsAsync(
        int daysAhead,
        bool onlyWithoutAutoRenew,
        CancellationToken cancellationToken = default)
    {
        var now = DateTime.UtcNow;
        var targetDate = now.AddDays(daysAhead);

        // 构建基础查询
        var query = dbContext.TenantSubscriptions
            .AsNoTracking()
            .Where(s => s.Status == SubscriptionStatus.Active
                     && s.EffectiveTo >= now
                     && s.EffectiveTo <= targetDate);

        // 如果只查询未开启自动续费的
        if (onlyWithoutAutoRenew)
        {
            query = query.Where(s => !s.AutoRenew);
        }

        // 连接租户和套餐信息
        var result = await query
            .Join(
                dbContext.Tenants,
                sub => sub.TenantId,
                tenant => tenant.Id,
                (sub, tenant) => new { Subscription = sub, Tenant = tenant }
            )
            .Join(
                dbContext.TenantPackages,
                combined => combined.Subscription.TenantPackageId,
                package => package.Id,
                (combined, package) => new ExpiringSubscriptionInfo
                {
                    Subscription = combined.Subscription,
                    TenantName = combined.Tenant.Name,
                    PackageName = package.Name
                }
            )
            .OrderBy(x => x.Subscription.EffectiveTo)
            .ToListAsync(cancellationToken);

        return result;
    }

    #endregion

    #region 收入统计

    /// <inheritdoc />
    public async Task<IReadOnlyList<TenantBillingStatement>> GetPaidBillsAsync(CancellationToken cancellationToken = default)
    {
        return await dbContext.TenantBillingStatements
            .AsNoTracking()
            .Where(b => b.Status == TenantBillingStatus.Paid)
            .ToListAsync(cancellationToken);
    }

    #endregion

    #region 配额使用排行

    /// <inheritdoc />
    public async Task<IReadOnlyList<QuotaUsageRankInfo>> GetQuotaUsageRankingAsync(
        TenantQuotaType quotaType,
        int topN,
        CancellationToken cancellationToken = default)
    {
        return await dbContext.TenantQuotaUsages
            .AsNoTracking()
            .Where(q => q.QuotaType == quotaType && q.LimitValue > 0)
            .Join(
                dbContext.Tenants,
                quota => quota.TenantId,
                tenant => tenant.Id,
                (quota, tenant) => new QuotaUsageRankInfo
                {
                    TenantId = quota.TenantId,
                    TenantName = tenant.Name,
                    UsedValue = quota.UsedValue,
                    LimitValue = quota.LimitValue,
                    UsagePercentage = quota.LimitValue > 0 ? (quota.UsedValue / quota.LimitValue * 100) : 0
                }
            )
            .OrderByDescending(x => x.UsagePercentage)
            .Take(topN)
            .ToListAsync(cancellationToken);
    }

    #endregion
}
