using ColaFlow.Shared.Kernel.Common;

namespace ColaFlow.Modules.Identity.Domain.Entities;

/// <summary>
/// Represents rate limiting tracking for email operations (verification, password reset, invitations)
/// Persists in database to survive server restarts and prevent email bombing attacks
/// </summary>
public sealed class EmailRateLimit : Entity
{
    /// <summary>
    /// Email address (normalized to lowercase)
    /// </summary>
    public string Email { get; private set; } = null!;

    /// <summary>
    /// Tenant ID associated with this email operation
    /// </summary>
    public Guid TenantId { get; private set; }

    /// <summary>
    /// Type of email operation: 'verification', 'password_reset', 'invitation'
    /// </summary>
    public string OperationType { get; private set; } = null!;

    /// <summary>
    /// Timestamp of the last email sent
    /// </summary>
    public DateTime LastSentAt { get; private set; }

    /// <summary>
    /// Number of attempts within the current time window
    /// </summary>
    public int AttemptsCount { get; private set; }

    /// <summary>
    /// Private constructor for EF Core
    /// </summary>
    private EmailRateLimit() : base()
    {
    }

    /// <summary>
    /// Factory method to create a new rate limit record
    /// </summary>
    public static EmailRateLimit Create(string email, Guid tenantId, string operationType)
    {
        if (string.IsNullOrWhiteSpace(email))
            throw new ArgumentException("Email cannot be empty", nameof(email));

        if (string.IsNullOrWhiteSpace(operationType))
            throw new ArgumentException("Operation type cannot be empty", nameof(operationType));

        return new EmailRateLimit
        {
            Id = Guid.NewGuid(),
            Email = email.ToLower(),
            TenantId = tenantId,
            OperationType = operationType,
            LastSentAt = DateTime.UtcNow,
            AttemptsCount = 1
        };
    }

    /// <summary>
    /// Record a new attempt (increment counter)
    /// </summary>
    public void RecordAttempt()
    {
        AttemptsCount++;
        LastSentAt = DateTime.UtcNow;
    }

    /// <summary>
    /// Reset attempts counter (when time window expires)
    /// </summary>
    public void ResetAttempts()
    {
        LastSentAt = DateTime.UtcNow;
        AttemptsCount = 1;
    }

    /// <summary>
    /// Check if the time window has expired
    /// </summary>
    public bool IsWindowExpired(TimeSpan window)
    {
        return DateTime.UtcNow - LastSentAt > window;
    }
}
