from beanie import Document
from pydantic import EmailStr, Field, validator
from typing import Optional, List
from datetime import datetime, timedelta
from enum import Enum

class UserStatus(str, Enum):
    ACTIVE = "active"
    INACTIVE = "inactive"
    SUSPENDED = "suspended"
    PENDING_VERIFICATION = "pending_verification"

class User(Document):
    email: EmailStr
    username: str = Field(..., min_length=3, max_length=50)
    password_hash: str
    status: UserStatus = UserStatus.ACTIVE
    
    # Security fields
    failed_login_attempts: int = 0
    last_login_attempt: Optional[datetime] = None
    locked_until: Optional[datetime] = None
    last_successful_login: Optional[datetime] = None
    
    # Verification
    email_verified: bool = True
    email_verification_token: Optional[str] = None
    email_verification_expires: Optional[datetime] = None
    
    # Password reset
    password_reset_token: Optional[str] = None
    password_reset_expires: Optional[datetime] = None
    password_changed_at: Optional[datetime] = None
    
    # Timestamps
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)
    
    # Device tracking
    login_devices: List[str] = Field(default_factory=list)  # Store device fingerprints
    
    class Settings:
        name = "users"
        indexes = [
            "email",
            "username",
            "status",
            "email_verification_token",
            "password_reset_token",
            "created_at"
        ]

    class Config:
        arbitrary_types_allowed = True

    def is_locked(self) -> bool:
        """Check if user account is locked"""
        if self.locked_until and datetime.utcnow() < self.locked_until:
            return True
        return False

    def is_active(self) -> bool:
        """Check if user is active and not locked"""
        return self.status == UserStatus.ACTIVE and not self.is_locked()
    
    def can_login(self) -> bool:
        """Check if user can attempt to login"""
        return self.status in [UserStatus.ACTIVE, UserStatus.PENDING_VERIFICATION] and not self.is_locked()

    async def increment_failed_attempts(self):
        """Increment failed login attempts and lock if necessary"""
        from shared.config import settings
        
        self.failed_login_attempts += 1
        self.last_login_attempt = datetime.utcnow()
        
        if self.failed_login_attempts >= settings.max_login_attempts:
            self.locked_until = datetime.utcnow() + timedelta(seconds=settings.account_lockout_duration)
        
        await self.save()

    async def reset_failed_attempts(self):
        """Reset failed login attempts on successful login"""
        self.failed_login_attempts = 0
        self.locked_until = None
        self.last_successful_login = datetime.utcnow()
        await self.save()
