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

namespace TakeoutSaaS.Domain.Tenants.Entities;

/// <summary>
/// 租户账单，用于呈现周期性收费。
/// </summary>
public sealed class TenantBillingStatement : MultiTenantEntityBase
{
    /// <summary>
    /// 账单编号，供对账查询。
    /// </summary>
    public string StatementNo { get; set; } = string.Empty;

    /// <summary>
    /// 账单类型（订阅账单/配额包账单/手动账单/续费账单）。
    /// </summary>
    public BillingType BillingType { get; set; } = BillingType.Subscription;

    /// <summary>
    /// 关联的订阅 ID（仅当 BillingType 为 Subscription 或 Renewal 时有值）。
    /// </summary>
    public long? SubscriptionId { get; set; }

    /// <summary>
    /// 账单周期开始时间。
    /// </summary>
    public DateTime PeriodStart { get; set; }

    /// <summary>
    /// 账单周期结束时间。
    /// </summary>
    public DateTime PeriodEnd { get; set; }

    /// <summary>
    /// 应付金额（原始金额）。
    /// </summary>
    public decimal AmountDue { get; set; }

    /// <summary>
    /// 折扣金额。
    /// </summary>
    public decimal DiscountAmount { get; set; }

    /// <summary>
    /// 税费金额。
    /// </summary>
    public decimal TaxAmount { get; set; }

    /// <summary>
    /// 实付金额。
    /// </summary>
    public decimal AmountPaid { get; set; }

    /// <summary>
    /// 货币类型（默认 CNY）。
    /// </summary>
    public string Currency { get; set; } = "CNY";

    /// <summary>
    /// 当前付款状态。
    /// </summary>
    public TenantBillingStatus Status { get; set; } = TenantBillingStatus.Pending;

    /// <summary>
    /// 到期日。
    /// </summary>
    public DateTime DueDate { get; set; }

    /// <summary>
    /// 提醒发送时间（续费提醒、逾期提醒等）。
    /// </summary>
    public DateTime? ReminderSentAt { get; set; }

    /// <summary>
    /// 逾期通知时间。
    /// </summary>
    public DateTime? OverdueNotifiedAt { get; set; }

    /// <summary>
    /// 账单明细 JSON，记录各项费用。
    /// </summary>
    public string? LineItemsJson { get; set; }

    /// <summary>
    /// 备注信息（如：人工备注、取消原因等）。
    /// </summary>
    public string? Notes { get; set; }

    /// <summary>
    /// 计算总金额（应付金额 - 折扣 + 税费）。
    /// </summary>
    /// <returns>总金额。</returns>
    public decimal CalculateTotalAmount()
    {
        return AmountDue - DiscountAmount + TaxAmount;
    }

    /// <summary>
    /// 标记为已支付（直接结清）。
    /// </summary>
    public void MarkAsPaid()
    {
        // 1. 计算剩余应付金额
        var remainingAmount = CalculateTotalAmount() - AmountPaid;

        // 2. 若已结清则直接返回
        if (remainingAmount <= 0)
        {
            Status = TenantBillingStatus.Paid;
            return;
        }

        // 3. 补足剩余金额并标记为已支付
        MarkAsPaid(remainingAmount, string.Empty);
    }

    /// <summary>
    /// 标记为已支付。
    /// </summary>
    /// <param name="amount">支付金额。</param>
    /// <param name="transactionNo">交易号。</param>
    public void MarkAsPaid(decimal amount, string transactionNo)
    {
        if (Status == TenantBillingStatus.Paid)
        {
            throw new InvalidOperationException("账单已经处于已支付状态，不能重复标记。");
        }

        if (Status == TenantBillingStatus.Cancelled)
        {
            throw new InvalidOperationException("已取消的账单不能标记为已支付。");
        }

        // 1. 累加支付金额
        AmountPaid += amount;

        // 2. 如果实付金额大于等于应付总额，则标记为已支付
        if (AmountPaid >= CalculateTotalAmount())
        {
            Status = TenantBillingStatus.Paid;
        }
    }

    /// <summary>
    /// 标记为逾期。
    /// </summary>
    public void MarkAsOverdue()
    {
        // 1. 仅待支付账单允许标记逾期
        if (Status != TenantBillingStatus.Pending)
        {
            return;
        }

        // 2. 未超过到期日则不处理
        if (DateTime.UtcNow <= DueDate)
        {
            return;
        }

        // 3. 标记为逾期（通知时间由外部流程在发送通知时写入）
        Status = TenantBillingStatus.Overdue;
    }

    /// <summary>
    /// 取消账单。
    /// </summary>
    public void Cancel()
    {
        Cancel(null);
    }

    /// <summary>
    /// 取消账单。
    /// </summary>
    /// <param name="reason">取消原因。</param>
    public void Cancel(string? reason)
    {
        if (Status == TenantBillingStatus.Paid)
        {
            throw new InvalidOperationException("已支付的账单不能取消。");
        }

        if (Status == TenantBillingStatus.Cancelled)
        {
            throw new InvalidOperationException("账单已经处于取消状态。");
        }

        // 1. 变更状态
        Status = TenantBillingStatus.Cancelled;

        // 2. 记录取消原因（可选）
        if (!string.IsNullOrWhiteSpace(reason))
        {
            Notes = string.IsNullOrWhiteSpace(Notes) ? $"[取消原因] {reason}" : $"{Notes}\n[取消原因] {reason}";
        }
    }
}
