using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;

namespace TakeoutSaaS.Domain.Tenants.Repositories;

/// <summary>
/// 订阅管理仓储接口。
/// </summary>
public interface ISubscriptionRepository
{
    #region 订阅查询

    /// <summary>
    /// 按 ID 查询订阅。
    /// </summary>
    /// <param name="subscriptionId">订阅 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>订阅实体，未找到返回 null。</returns>
    Task<TenantSubscription?> FindByIdAsync(
        long subscriptionId,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// 按 ID 列表批量查询订阅。
    /// </summary>
    /// <param name="subscriptionIds">订阅 ID 列表。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>订阅实体列表。</returns>
    Task<IReadOnlyList<TenantSubscription>> FindByIdsAsync(
        IEnumerable<long> subscriptionIds,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// 分页查询订阅列表（含关联信息）。
    /// </summary>
    /// <param name="filter">查询过滤条件。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>分页结果。</returns>
    Task<(IReadOnlyList<SubscriptionWithRelations> Items, int Total)> SearchPagedAsync(
        SubscriptionSearchFilter filter,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取订阅详情（含关联信息）。
    /// </summary>
    /// <param name="subscriptionId">订阅 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>订阅详情信息。</returns>
    Task<SubscriptionDetailInfo?> GetDetailAsync(
        long subscriptionId,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// 按 ID 列表批量查询订阅（含租户信息）。
    /// </summary>
    /// <param name="subscriptionIds">订阅 ID 列表。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>订阅与租户信息列表。</returns>
    Task<IReadOnlyList<SubscriptionWithTenant>> FindByIdsWithTenantAsync(
        IEnumerable<long> subscriptionIds,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// 查询自动续费候选订阅（活跃 + 开启自动续费 + 即将到期）。
    /// </summary>
    /// <param name="now">当前时间（UTC）。</param>
    /// <param name="renewalThreshold">续费阈值时间（UTC），到期时间小于等于该时间视为候选。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>候选订阅集合（含套餐信息）。</returns>
    Task<IReadOnlyList<AutoRenewalCandidate>> FindAutoRenewalCandidatesAsync(
        DateTime now,
        DateTime renewalThreshold,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// 查询续费提醒候选订阅（活跃 + 未开启自动续费 + 到期时间落在指定日期范围）。
    /// </summary>
    /// <param name="startOfDay">筛选开始时间（UTC，含）。</param>
    /// <param name="endOfDay">筛选结束时间（UTC，不含）。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>候选订阅集合（含租户与套餐信息）。</returns>
    Task<IReadOnlyList<RenewalReminderCandidate>> FindRenewalReminderCandidatesAsync(
        DateTime startOfDay,
        DateTime endOfDay,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// 查询已到期仍处于 Active 的订阅（用于进入宽限期）。
    /// </summary>
    /// <param name="now">当前时间（UTC）。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>到期订阅集合。</returns>
    Task<IReadOnlyList<TenantSubscription>> FindExpiredActiveSubscriptionsAsync(
        DateTime now,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// 查询宽限期已结束的订阅（用于自动暂停）。
    /// </summary>
    /// <param name="now">当前时间（UTC）。</param>
    /// <param name="gracePeriodDays">宽限期天数。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>宽限期到期订阅集合。</returns>
    Task<IReadOnlyList<TenantSubscription>> FindGracePeriodExpiredSubscriptionsAsync(
        DateTime now,
        int gracePeriodDays,
        CancellationToken cancellationToken = default);

    #endregion

    #region 套餐查询

    /// <summary>
    /// 按 ID 查询套餐。
    /// </summary>
    /// <param name="packageId">套餐 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>套餐实体，未找到返回 null。</returns>
    Task<TenantPackage?> FindPackageByIdAsync(long packageId, CancellationToken cancellationToken = default);

    #endregion

    #region 订阅更新

    /// <summary>
    /// 更新订阅。
    /// </summary>
    /// <param name="subscription">订阅实体。</param>
    /// <param name="cancellationToken">取消标记。</param>
    Task UpdateAsync(TenantSubscription subscription, CancellationToken cancellationToken = default);

    #endregion

    #region 订阅历史

    /// <summary>
    /// 添加订阅变更历史。
    /// </summary>
    /// <param name="history">历史记录实体。</param>
    /// <param name="cancellationToken">取消标记。</param>
    Task AddHistoryAsync(TenantSubscriptionHistory history, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取订阅变更历史（含套餐名称）。
    /// </summary>
    /// <param name="subscriptionId">订阅 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>历史记录列表。</returns>
    Task<IReadOnlyList<SubscriptionHistoryWithPackageNames>> GetHistoryAsync(
        long subscriptionId,
        CancellationToken cancellationToken = default);

    #endregion

    #region 配额使用

    /// <summary>
    /// 获取租户配额使用情况。
    /// </summary>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>配额使用列表。</returns>
    Task<IReadOnlyList<TenantQuotaUsage>> GetQuotaUsagesAsync(
        long tenantId,
        CancellationToken cancellationToken = default);

    #endregion

    #region 通知

    /// <summary>
    /// 添加租户通知。
    /// </summary>
    /// <param name="notification">通知实体。</param>
    /// <param name="cancellationToken">取消标记。</param>
    Task AddNotificationAsync(TenantNotification notification, CancellationToken cancellationToken = default);

    #endregion

    #region 操作日志

    /// <summary>
    /// 添加操作日志。
    /// </summary>
    /// <param name="log">日志实体。</param>
    /// <param name="cancellationToken">取消标记。</param>
    Task AddOperationLogAsync(OperationLog log, CancellationToken cancellationToken = default);

    #endregion

    /// <summary>
    /// 保存变更。
    /// </summary>
    /// <param name="cancellationToken">取消标记。</param>
    Task SaveChangesAsync(CancellationToken cancellationToken = default);
}

#region 查询过滤与结果类型

/// <summary>
/// 订阅查询过滤条件。
/// </summary>
public record SubscriptionSearchFilter
{
    /// <summary>
    /// 订阅状态。
    /// </summary>
    public SubscriptionStatus? Status { get; init; }

    /// <summary>
    /// 套餐 ID。
    /// </summary>
    public long? TenantPackageId { get; init; }

    /// <summary>
    /// 租户 ID。
    /// </summary>
    public long? TenantId { get; init; }

    /// <summary>
    /// 租户关键词（名称或编码）。
    /// </summary>
    public string? TenantKeyword { get; init; }

    /// <summary>
    /// 即将到期天数。
    /// </summary>
    public int? ExpiringWithinDays { get; init; }

    /// <summary>
    /// 自动续费状态。
    /// </summary>
    public bool? AutoRenew { get; init; }

    /// <summary>
    /// 页码（从 1 开始）。
    /// </summary>
    public int Page { get; init; } = 1;

    /// <summary>
    /// 每页数量。
    /// </summary>
    public int PageSize { get; init; } = 20;
}

/// <summary>
/// 订阅及关联信息。
/// </summary>
public record SubscriptionWithRelations
{
    /// <summary>
    /// 订阅实体。
    /// </summary>
    public required TenantSubscription Subscription { get; init; }

    /// <summary>
    /// 租户名称。
    /// </summary>
    public required string TenantName { get; init; }

    /// <summary>
    /// 租户编码。
    /// </summary>
    public required string TenantCode { get; init; }

    /// <summary>
    /// 套餐名称。
    /// </summary>
    public required string PackageName { get; init; }

    /// <summary>
    /// 排期套餐名称（可选）。
    /// </summary>
    public string? ScheduledPackageName { get; init; }
}

/// <summary>
/// 订阅详情信息。
/// </summary>
public record SubscriptionDetailInfo
{
    /// <summary>
    /// 订阅实体。
    /// </summary>
    public required TenantSubscription Subscription { get; init; }

    /// <summary>
    /// 租户名称。
    /// </summary>
    public required string TenantName { get; init; }

    /// <summary>
    /// 租户编码。
    /// </summary>
    public required string TenantCode { get; init; }

    /// <summary>
    /// 当前套餐。
    /// </summary>
    public TenantPackage? Package { get; init; }

    /// <summary>
    /// 排期套餐。
    /// </summary>
    public TenantPackage? ScheduledPackage { get; init; }
}

/// <summary>
/// 订阅与租户信息。
/// </summary>
public record SubscriptionWithTenant
{
    /// <summary>
    /// 订阅实体。
    /// </summary>
    public required TenantSubscription Subscription { get; init; }

    /// <summary>
    /// 租户实体。
    /// </summary>
    public required Tenant Tenant { get; init; }
}

/// <summary>
/// 自动续费候选订阅信息。
/// </summary>
public sealed record AutoRenewalCandidate
{
    /// <summary>
    /// 订阅实体。
    /// </summary>
    public required TenantSubscription Subscription { get; init; }

    /// <summary>
    /// 当前套餐实体。
    /// </summary>
    public required TenantPackage Package { get; init; }
}

/// <summary>
/// 续费提醒候选订阅信息。
/// </summary>
public sealed record RenewalReminderCandidate
{
    /// <summary>
    /// 订阅实体。
    /// </summary>
    public required TenantSubscription Subscription { get; init; }

    /// <summary>
    /// 租户实体。
    /// </summary>
    public required Tenant Tenant { get; init; }

    /// <summary>
    /// 当前套餐实体。
    /// </summary>
    public required TenantPackage Package { get; init; }
}

/// <summary>
/// 订阅历史（含套餐名称）。
/// </summary>
public record SubscriptionHistoryWithPackageNames
{
    /// <summary>
    /// 历史记录实体。
    /// </summary>
    public required TenantSubscriptionHistory History { get; init; }

    /// <summary>
    /// 原套餐名称。
    /// </summary>
    public required string FromPackageName { get; init; }

    /// <summary>
    /// 目标套餐名称。
    /// </summary>
    public required string ToPackageName { get; init; }
}

#endregion
