using FlatRender.IdentitySvc.Domain.Enums;

namespace FlatRender.IdentitySvc.Domain.Entities;

public class User
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public Guid TenantId { get; set; }
    public Tenant Tenant { get; set; } = default!;

    // Auth
    public string? Email { get; set; }
    public bool EmailVerified { get; set; }
    public DateTime? EmailVerifiedAt { get; set; }
    public string? PhoneNumber { get; set; }
    public string? PhoneCountryCode { get; set; }
    public bool PhoneVerified { get; set; }
    public DateTime? PhoneVerifiedAt { get; set; }
    public string? PasswordHash { get; set; }
    public DateTime? PasswordSetAt { get; set; }
    public DateTime? LastPasswordResetDate { get; set; }
    public RegisterMode RegisterMode { get; set; } = RegisterMode.Email;
    public string? ExternalProvider { get; set; }
    public string? ExternalProviderId { get; set; }

    // Profile
    public string? FullName { get; set; }
    public string? AvatarUrl { get; set; }
    public DateOnly? BirthDate { get; set; }
    public GenderKind? Gender { get; set; }
    public string? NationalCode { get; set; }
    public string? CountryCode { get; set; }
    public string? CompanyName { get; set; }
    public string? WebsiteName { get; set; }
    public string? Slogan { get; set; }
    public string? AboutMe { get; set; }
    public string? MethodOfIntroduction { get; set; }

    // Balances
    public long BalanceMinor { get; set; }
    public long AffiliateBalanceMinor { get; set; }
    public Guid? AffiliateOwnerId { get; set; }
    public decimal ProfitPercentage { get; set; }

    // Gamification
    public int LoyaltyScore { get; set; }
    public int PurplePoint { get; set; }

    // Render quotas
    public int DailyRemainRenderCount { get; set; }
    public int MaxDailyRenderCount { get; set; }
    public DateTime? DailyRendersResetAt { get; set; }
    public int ParallelRenderingCeiling { get; set; } = 1;
    public int UserDailyFreeChargeSec { get; set; }
    public DateTime? DailyFreeChargeResetDate { get; set; }
    public int MaxPreviewDurationSec { get; set; } = 30;
    public bool ForceRenderQueue { get; set; }
    public bool RemoveWatermarkService { get; set; }

    // Telegram
    public string? TelegramId { get; set; }
    public bool TelegramTellMe { get; set; }

    // Comms prefs
    public bool EmailTellMe { get; set; } = true;
    public bool SmsTellMe { get; set; }
    public bool PushTellMe { get; set; } = true;

    // Storage
    public string? StorageEndpoint { get; set; }
    public long UsedStorageBytes { get; set; }

    // Status
    public bool IsAdmin { get; set; }
    public bool IsTenantAdmin { get; set; }
    public bool BanAccount { get; set; }
    public string? BanReason { get; set; }
    public DateTime? UnblockDate { get; set; }

    // Activity
    public DateTime? LastActiveDate { get; set; }
    public DateTime? LastLoginAt { get; set; }
    public string? LastLoginIp { get; set; }
    public bool RegisteredWithMobileApp { get; set; }
    public DateTime RegisterDate { get; set; } = DateTime.UtcNow;

    public string Metadata { get; set; } = "{}";
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
    public DateTime? DeletedAt { get; set; }

    public ICollection<UserSession> Sessions { get; set; } = [];
    public ICollection<MfaFactor> MfaFactors { get; set; } = [];
    public ICollection<PushSubscription> PushSubscriptions { get; set; } = [];
    public ICollection<UserPlan> Plans { get; set; } = [];
    public ICollection<Payment> Payments { get; set; } = [];
}

public class UserSession
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public Guid UserId { get; set; }
    public User User { get; set; } = default!;
    public Guid TenantId { get; set; }

    public string RefreshTokenHash { get; set; } = default!;
    public string? DeviceId { get; set; }
    public string? DeviceName { get; set; }
    public string? UserAgent { get; set; }
    public string? IpAddress { get; set; }

    public DateTime IssuedAt { get; set; } = DateTime.UtcNow;
    public DateTime ExpiresAt { get; set; }
    public DateTime? RevokedAt { get; set; }
    public DateTime? LastUsedAt { get; set; }
}

public class ConfirmationToken
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public Guid? UserId { get; set; }
    public Guid TenantId { get; set; }
    public TokenPurpose Purpose { get; set; }

    public string Identifier { get; set; } = default!;
    public string? NextIdentifier { get; set; }
    public string TokenHash { get; set; } = default!;
    public string? Code { get; set; }

    public bool IsConsumed { get; set; }
    public DateTime? ConsumedAt { get; set; }
    public int TryCount { get; set; }
    public int MaxTries { get; set; } = 5;

    public string? RequestIp { get; set; }
    public DateTime ExpiresAt { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

public class PushSubscription
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public Guid UserId { get; set; }
    public User User { get; set; } = default!;
    public Guid TenantId { get; set; }

    public string Endpoint { get; set; } = default!;
    public string P256dhKey { get; set; } = default!;
    public string AuthKey { get; set; } = default!;
    public string? UserAgent { get; set; }

    public bool IsActive { get; set; } = true;
    public DateTime? LastUsedAt { get; set; }
    public int FailureCount { get; set; }
    public DateTime? LastFailureAt { get; set; }
    public int? LastFailureStatus { get; set; }

    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

public class MfaFactor
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public Guid UserId { get; set; }
    public User User { get; set; } = default!;
    public MfaFactorType FactorType { get; set; }
    public string? SecretEncrypted { get; set; }
    public bool IsVerified { get; set; }
    public bool IsPrimary { get; set; }
    public string? Label { get; set; }
    public DateTime? LastUsedAt { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
