// ==============================================================================
// MORPH-SPEC - Subscription Model Template
// Modelo de assinatura para SaaS
// ==============================================================================

using System.ComponentModel.DataAnnotations;

namespace {{Namespace}}.Domain.Entities;

// ==============================================================================
// SUBSCRIPTION ENTITY
// ==============================================================================

public class Subscription : BaseEntity
{
    public int TenantId { get; private set; }
    public Tenant Tenant { get; private set; } = null!;

    public int PlanId { get; private set; }
    public Plan Plan { get; private set; } = null!;

    public SubscriptionStatus Status { get; private set; }
    public BillingCycle Cycle { get; private set; }

    public DateTime StartDate { get; private set; }
    public DateTime? EndDate { get; private set; }
    public DateTime? CancelledAt { get; private set; }
    public DateTime NextBillingDate { get; private set; }

    public decimal CurrentPrice { get; private set; }
    public string? ExternalSubscriptionId { get; private set; } // Asaas subscription ID

    public ICollection<SubscriptionPayment> Payments { get; private set; } = new List<SubscriptionPayment>();

    // =========================================================================
    // FACTORY
    // =========================================================================

    public static Subscription Create(int tenantId, int planId, BillingCycle cycle, decimal price)
    {
        return new Subscription
        {
            TenantId = tenantId,
            PlanId = planId,
            Status = SubscriptionStatus.PendingPayment,
            Cycle = cycle,
            StartDate = DateTime.UtcNow,
            NextBillingDate = DateTime.UtcNow,
            CurrentPrice = price,
            CreatedAt = DateTime.UtcNow
        };
    }

    // =========================================================================
    // BEHAVIORS
    // =========================================================================

    public void Activate(string externalSubscriptionId)
    {
        Status = SubscriptionStatus.Active;
        ExternalSubscriptionId = externalSubscriptionId;
        UpdatedAt = DateTime.UtcNow;
    }

    public void Suspend()
    {
        Status = SubscriptionStatus.Suspended;
        UpdatedAt = DateTime.UtcNow;
    }

    public void Cancel(DateTime? endDate = null)
    {
        Status = SubscriptionStatus.Cancelled;
        CancelledAt = DateTime.UtcNow;
        EndDate = endDate ?? DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }

    public void Renew()
    {
        NextBillingDate = CalculateNextBillingDate();
        UpdatedAt = DateTime.UtcNow;
    }

    public void ChangePlan(int newPlanId, decimal newPrice)
    {
        PlanId = newPlanId;
        CurrentPrice = newPrice;
        UpdatedAt = DateTime.UtcNow;
    }

    public void AddPayment(SubscriptionPayment payment)
    {
        Payments.Add(payment);
    }

    // =========================================================================
    // QUERIES
    // =========================================================================

    public bool IsActive => Status == SubscriptionStatus.Active;
    public bool IsCancelled => Status == SubscriptionStatus.Cancelled;
    public bool IsSuspended => Status == SubscriptionStatus.Suspended;
    public bool IsExpired => EndDate.HasValue && EndDate.Value < DateTime.UtcNow;

    public int DaysUntilRenewal => (NextBillingDate - DateTime.UtcNow).Days;
    public bool IsNearRenewal => DaysUntilRenewal <= 3;

    private DateTime CalculateNextBillingDate()
    {
        return Cycle switch
        {
            BillingCycle.Monthly => NextBillingDate.AddMonths(1),
            BillingCycle.Quarterly => NextBillingDate.AddMonths(3),
            BillingCycle.Yearly => NextBillingDate.AddYears(1),
            _ => NextBillingDate.AddMonths(1)
        };
    }
}

// ==============================================================================
// SUBSCRIPTION PAYMENT ENTITY
// ==============================================================================

public class SubscriptionPayment : BaseEntity
{
    public int SubscriptionId { get; private set; }
    public Subscription Subscription { get; private set; } = null!;

    public decimal Amount { get; private set; }
    public PaymentStatus Status { get; private set; }
    public PaymentMethod Method { get; private set; }

    public DateTime DueDate { get; private set; }
    public DateTime? PaidAt { get; private set; }

    public string? ExternalPaymentId { get; private set; } // Asaas payment ID
    public string? InvoiceUrl { get; private set; }
    public string? BoletoUrl { get; private set; }
    public string? PixQrCode { get; private set; }
    public string? PixPayload { get; private set; }

    // =========================================================================
    // FACTORY
    // =========================================================================

    public static SubscriptionPayment Create(
        int subscriptionId,
        decimal amount,
        PaymentMethod method,
        DateTime dueDate)
    {
        return new SubscriptionPayment
        {
            SubscriptionId = subscriptionId,
            Amount = amount,
            Status = PaymentStatus.Pending,
            Method = method,
            DueDate = dueDate,
            CreatedAt = DateTime.UtcNow
        };
    }

    // =========================================================================
    // BEHAVIORS
    // =========================================================================

    public void SetExternalId(string externalPaymentId)
    {
        ExternalPaymentId = externalPaymentId;
        UpdatedAt = DateTime.UtcNow;
    }

    public void SetPaymentUrls(string? invoiceUrl, string? boletoUrl)
    {
        InvoiceUrl = invoiceUrl;
        BoletoUrl = boletoUrl;
        UpdatedAt = DateTime.UtcNow;
    }

    public void SetPixData(string qrCode, string payload)
    {
        PixQrCode = qrCode;
        PixPayload = payload;
        UpdatedAt = DateTime.UtcNow;
    }

    public void MarkAsPaid()
    {
        Status = PaymentStatus.Paid;
        PaidAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }

    public void MarkAsOverdue()
    {
        Status = PaymentStatus.Overdue;
        UpdatedAt = DateTime.UtcNow;
    }

    public void MarkAsRefunded()
    {
        Status = PaymentStatus.Refunded;
        UpdatedAt = DateTime.UtcNow;
    }
}

// ==============================================================================
// PLAN ENTITY
// ==============================================================================

public class Plan : BaseEntity
{
    [Required]
    [MaxLength(100)]
    public string Name { get; private set; } = string.Empty;

    [MaxLength(500)]
    public string? Description { get; private set; }

    public decimal MonthlyPrice { get; private set; }
    public decimal YearlyPrice { get; private set; }

    public int MaxUsers { get; private set; }
    public long MaxStorageBytes { get; private set; }

    public bool IsActive { get; private set; }
    public int SortOrder { get; private set; }

    public ICollection<PlanFeature> Features { get; private set; } = new List<PlanFeature>();

    // =========================================================================
    // FACTORY
    // =========================================================================

    public static Plan Create(
        string name,
        decimal monthlyPrice,
        decimal yearlyPrice,
        int maxUsers,
        long maxStorageBytes)
    {
        return new Plan
        {
            Name = name,
            MonthlyPrice = monthlyPrice,
            YearlyPrice = yearlyPrice,
            MaxUsers = maxUsers,
            MaxStorageBytes = maxStorageBytes,
            IsActive = true,
            CreatedAt = DateTime.UtcNow
        };
    }

    // =========================================================================
    // QUERIES
    // =========================================================================

    public decimal GetPrice(BillingCycle cycle) => cycle switch
    {
        BillingCycle.Monthly => MonthlyPrice,
        BillingCycle.Quarterly => MonthlyPrice * 3 * 0.95m, // 5% discount
        BillingCycle.Yearly => YearlyPrice,
        _ => MonthlyPrice
    };

    public decimal YearlySavings => (MonthlyPrice * 12) - YearlyPrice;
    public int YearlySavingsPercent => (int)((YearlySavings / (MonthlyPrice * 12)) * 100);
}

// ==============================================================================
// PLAN FEATURE ENTITY
// ==============================================================================

public class PlanFeature
{
    public int Id { get; private set; }
    public int PlanId { get; private set; }
    public Plan Plan { get; private set; } = null!;

    [Required]
    [MaxLength(100)]
    public string Name { get; private set; } = string.Empty;

    [MaxLength(200)]
    public string? Description { get; private set; }

    public bool IsIncluded { get; private set; }
    public int? Limit { get; private set; } // null = unlimited

    public static PlanFeature Create(string name, bool isIncluded, int? limit = null)
    {
        return new PlanFeature
        {
            Name = name,
            IsIncluded = isIncluded,
            Limit = limit
        };
    }
}

// ==============================================================================
// ENUMS
// ==============================================================================

public enum SubscriptionStatus
{
    PendingPayment,
    Active,
    Suspended,
    Cancelled,
    Expired
}

public enum BillingCycle
{
    Monthly,
    Quarterly,
    Yearly
}

public enum PaymentStatus
{
    Pending,
    Paid,
    Overdue,
    Refunded,
    Cancelled
}

public enum PaymentMethod
{
    Pix,
    Boleto,
    CreditCard
}

// ==============================================================================
// BASE ENTITY
// ==============================================================================

public abstract class BaseEntity
{
    public int Id { get; protected set; }
    public DateTime CreatedAt { get; protected set; }
    public DateTime? UpdatedAt { get; protected set; }
}
