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>
/// 订阅仓储实现（AdminApi 使用）。
/// </summary>
public sealed class EfSubscriptionRepository(TakeoutAdminDbContext context) : ISubscriptionRepository
{
    /// <inheritdoc />
    public async Task<(IReadOnlyList<SubscriptionListResult> Items, int TotalCount)> GetListAsync(
        SubscriptionStatus? status,
        long? tenantPackageId,
        long? tenantId,
        string? tenantKeyword,
        int? expiringWithinDays,
        bool? autoRenew,
        DateTime? expireFrom,
        DateTime? expireTo,
        int page,
        int pageSize,
        CancellationToken cancellationToken = default)
    {
        // 1. 获取当前时间
        var now = DateTime.UtcNow;

        // 2. 构建基础查询
        var query = from s in context.TenantSubscriptions.AsNoTracking()
                    join t in context.Tenants.AsNoTracking() on s.TenantId equals t.Id
                    join p in context.TenantPackages.AsNoTracking() on s.TenantPackageId equals p.Id
                    where s.DeletedAt == null && t.DeletedAt == null
                    select new
                    {
                        Subscription = s,
                        Tenant = t,
                        Package = p,
                        ScheduledPackage = context.TenantPackages
                            .Where(sp => sp.Id == s.ScheduledPackageId)
                            .Select(sp => new { sp.Id, sp.Name })
                            .FirstOrDefault()
                    };

        // 3. 应用订阅状态过滤
        if (status.HasValue)
        {
            query = query.Where(x => x.Subscription.Status == status.Value);
        }

        // 4. 应用套餐 ID 过滤
        if (tenantPackageId.HasValue)
        {
            query = query.Where(x => x.Subscription.TenantPackageId == tenantPackageId.Value);
        }

        // 5. 应用租户 ID 过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.Subscription.TenantId == tenantId.Value);
        }

        // 6. 应用租户关键词过滤
        if (!string.IsNullOrWhiteSpace(tenantKeyword))
        {
            var normalized = tenantKeyword.Trim();
            query = query.Where(x => x.Tenant.Name.Contains(normalized) || x.Tenant.Code.Contains(normalized));
        }

        // 7. 应用到期天数筛选
        if (expiringWithinDays.HasValue)
        {
            var expiryDate = now.AddDays(expiringWithinDays.Value);
            query = query.Where(x => x.Subscription.EffectiveTo <= expiryDate && x.Subscription.EffectiveTo > now);
        }

        // 8. 应用自动续费筛选
        if (autoRenew.HasValue)
        {
            query = query.Where(x => x.Subscription.AutoRenew == autoRenew.Value);
        }

        // 9. 应用到期时间范围筛选
        if (expireFrom.HasValue)
        {
            query = query.Where(x => x.Subscription.EffectiveTo >= expireFrom.Value);
        }

        if (expireTo.HasValue)
        {
            query = query.Where(x => x.Subscription.EffectiveTo <= expireTo.Value);
        }

        // 10. 获取总数
        var totalCount = await query.CountAsync(cancellationToken);

        // 11. 分页查询（按到期时间升序）
        var items = await query
            .OrderBy(x => x.Subscription.EffectiveTo)
            .ThenBy(x => x.Subscription.Id)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .Select(x => new SubscriptionListResult(
                x.Subscription.Id,
                x.Tenant.Id,
                x.Tenant.Name,
                x.Tenant.Code,
                x.Package.Id,
                x.Package.Name,
                x.ScheduledPackage != null ? x.ScheduledPackage.Id : (long?)null,
                x.ScheduledPackage != null ? x.ScheduledPackage.Name : null,
                x.Subscription.Status,
                x.Subscription.EffectiveFrom,
                x.Subscription.EffectiveTo,
                x.Subscription.NextBillingDate,
                x.Subscription.AutoRenew,
                x.Subscription.Notes,
                x.Subscription.CreatedAt,
                x.Subscription.UpdatedAt))
            .ToListAsync(cancellationToken);

        // 12. 返回结果
        return (items, totalCount);
    }

    /// <inheritdoc />
    public async Task<TenantSubscription?> GetByIdAsync(long subscriptionId, CancellationToken cancellationToken = default)
    {
        // 1. 查询订阅（排除已删除，无跟踪）
        return await context.TenantSubscriptions
            .AsNoTracking()
            .Where(s => s.Id == subscriptionId && s.DeletedAt == null)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<TenantSubscription?> GetByIdForUpdateAsync(long subscriptionId, CancellationToken cancellationToken = default)
    {
        // 1. 查询订阅（排除已删除，带跟踪用于更新）
        return await context.TenantSubscriptions
            .Where(s => s.Id == subscriptionId && s.DeletedAt == null)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        // 1. 保存变更
        await context.SaveChangesAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<SubscriptionDetailResult?> GetDetailAsync(long subscriptionId, CancellationToken cancellationToken = default)
    {
        // 1. 查询订阅详情
        var result = await (from s in context.TenantSubscriptions.AsNoTracking()
                           join t in context.Tenants.AsNoTracking() on s.TenantId equals t.Id
                           join p in context.TenantPackages.AsNoTracking() on s.TenantPackageId equals p.Id
                           where s.Id == subscriptionId && s.DeletedAt == null && t.DeletedAt == null
                           select new
                           {
                               Subscription = s,
                               Tenant = t,
                               Package = p,
                               ScheduledPackage = context.TenantPackages
                                   .Where(sp => sp.Id == s.ScheduledPackageId)
                                   .FirstOrDefault()
                           }).FirstOrDefaultAsync(cancellationToken);

        // 2. 如果不存在，返回 null
        if (result is null)
        {
            return null;
        }

        // 3. 返回详情结果
        return new SubscriptionDetailResult(
            result.Subscription.Id,
            result.Tenant.Id,
            result.Tenant.Name,
            result.Tenant.Code,
            result.Package.Id,
            result.Package.Name,
            result.ScheduledPackage?.Id,
            result.ScheduledPackage?.Name,
            result.Subscription.Status,
            result.Subscription.EffectiveFrom,
            result.Subscription.EffectiveTo,
            result.Subscription.NextBillingDate,
            result.Subscription.AutoRenew,
            result.Subscription.Notes,
            result.Subscription.CreatedAt,
            result.Subscription.UpdatedAt,
            result.Package,
            result.ScheduledPackage);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<SubscriptionHistoryResult>> GetHistoriesAsync(long subscriptionId, CancellationToken cancellationToken = default)
    {
        // 1. 查询变更历史
        var histories = await (from h in context.TenantSubscriptionHistories.AsNoTracking()
                              join fp in context.TenantPackages.AsNoTracking() on h.FromPackageId equals fp.Id
                              join tp in context.TenantPackages.AsNoTracking() on h.ToPackageId equals tp.Id
                              where h.TenantSubscriptionId == subscriptionId && h.DeletedAt == null
                              orderby h.CreatedAt descending
                              select new SubscriptionHistoryResult(
                                  h.Id,
                                  h.TenantSubscriptionId,
                                  h.ChangeType,
                                  h.FromPackageId,
                                  fp.Name,
                                  h.ToPackageId,
                                  tp.Name,
                                  h.EffectiveFrom,
                                  h.EffectiveTo,
                                  h.Notes,
                                  h.CreatedAt,
                                  h.CreatedBy))
                              .ToListAsync(cancellationToken);

        // 2. 返回结果
        return histories;
    }

    /// <inheritdoc />
    public async Task<SubscriptionListResult?> GetListResultByIdAsync(long subscriptionId, CancellationToken cancellationToken = default)
    {
        // 1. 查询订阅（带租户和套餐信息）
        var result = await (from s in context.TenantSubscriptions.AsNoTracking()
                          join t in context.Tenants.AsNoTracking() on s.TenantId equals t.Id
                          join p in context.TenantPackages.AsNoTracking() on s.TenantPackageId equals p.Id
                          where s.Id == subscriptionId && s.DeletedAt == null && t.DeletedAt == null
                          select new
                          {
                              Subscription = s,
                              Tenant = t,
                              Package = p,
                              ScheduledPackage = context.TenantPackages
                                  .Where(sp => sp.Id == s.ScheduledPackageId)
                                  .Select(sp => new { sp.Id, sp.Name })
                                  .FirstOrDefault()
                          }).FirstOrDefaultAsync(cancellationToken);

        // 2. 如果不存在，返回 null
        if (result is null)
        {
            return null;
        }

        // 3. 返回列表结果
        return new SubscriptionListResult(
            result.Subscription.Id,
            result.Tenant.Id,
            result.Tenant.Name,
            result.Tenant.Code,
            result.Package.Id,
            result.Package.Name,
            result.ScheduledPackage != null ? result.ScheduledPackage.Id : (long?)null,
            result.ScheduledPackage != null ? result.ScheduledPackage.Name : null,
            result.Subscription.Status,
            result.Subscription.EffectiveFrom,
            result.Subscription.EffectiveTo,
            result.Subscription.NextBillingDate,
            result.Subscription.AutoRenew,
            result.Subscription.Notes,
            result.Subscription.CreatedAt,
            result.Subscription.UpdatedAt);
    }
}
