"""
User domain entity
"""
from datetime import datetime
from enum import Enum
from typing import List, Optional
from uuid import UUID, uuid4

from pydantic import BaseModel, Field, EmailStr


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


class UserRole(str, Enum):
    """User role enumeration"""
    SUPER_ADMIN = "super_admin"
    ADMIN = "admin"
    MANAGER = "manager"
    USER = "user"
    VIEWER = "viewer"


class User(BaseModel):
    """User domain entity"""
    
    id: UUID = Field(default_factory=uuid4)
    email: EmailStr
    username: str = Field(..., min_length=3, max_length=50)
    first_name: str = Field(..., min_length=1, max_length=100)
    last_name: str = Field(..., min_length=1, max_length=100)
    hashed_password: str
    status: UserStatus = UserStatus.PENDING_VERIFICATION
    roles: List[UserRole] = Field(default_factory=lambda: [UserRole.USER])
    permissions: List[str] = Field(default_factory=list)
    
    # Profile Information
    avatar_url: Optional[str] = None
    phone_number: Optional[str] = None
    timezone: str = "UTC"
    language: str = "en"
    
    # Security
    is_email_verified: bool = False
    email_verification_token: Optional[str] = None
    password_reset_token: Optional[str] = None
    password_reset_expires: Optional[datetime] = None
    failed_login_attempts: int = 0
    locked_until: Optional[datetime] = None
    
    # Two-Factor Authentication
    is_2fa_enabled: bool = False
    totp_secret: Optional[str] = None
    backup_codes: List[str] = Field(default_factory=list)
    
    # OAuth
    google_id: Optional[str] = None
    github_id: Optional[str] = None
    
    # Metadata
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)
    last_login_at: Optional[datetime] = None
    last_activity_at: Optional[datetime] = None
    
    # Organization
    organization_id: Optional[UUID] = None
    department: Optional[str] = None
    job_title: Optional[str] = None
    
    class Config:
        use_enum_values = True
        json_encoders = {
            datetime: lambda v: v.isoformat(),
            UUID: lambda v: str(v)
        }
    
    @property
    def full_name(self) -> str:
        """Get user's full name"""
        return f"{self.first_name} {self.last_name}"
    
    @property
    def is_active(self) -> bool:
        """Check if user is active"""
        return self.status == UserStatus.ACTIVE
    
    @property
    def is_admin(self) -> bool:
        """Check if user has admin privileges"""
        return UserRole.ADMIN in self.roles or UserRole.SUPER_ADMIN in self.roles
    
    @property
    def is_locked(self) -> bool:
        """Check if user account is locked"""
        if self.locked_until is None:
            return False
        return datetime.utcnow() < self.locked_until
    
    def has_permission(self, permission: str) -> bool:
        """Check if user has specific permission"""
        return permission in self.permissions
    
    def has_role(self, role: UserRole) -> bool:
        """Check if user has specific role"""
        return role in self.roles
    
    def add_role(self, role: UserRole) -> None:
        """Add role to user"""
        if role not in self.roles:
            self.roles.append(role)
            self.updated_at = datetime.utcnow()
    
    def remove_role(self, role: UserRole) -> None:
        """Remove role from user"""
        if role in self.roles:
            self.roles.remove(role)
            self.updated_at = datetime.utcnow()
    
    def add_permission(self, permission: str) -> None:
        """Add permission to user"""
        if permission not in self.permissions:
            self.permissions.append(permission)
            self.updated_at = datetime.utcnow()
    
    def remove_permission(self, permission: str) -> None:
        """Remove permission from user"""
        if permission in self.permissions:
            self.permissions.remove(permission)
            self.updated_at = datetime.utcnow()
    
    def update_last_login(self) -> None:
        """Update last login timestamp"""
        self.last_login_at = datetime.utcnow()
        self.last_activity_at = datetime.utcnow()
        self.failed_login_attempts = 0
        self.locked_until = None
    
    def increment_failed_login(self, max_attempts: int = 5, lockout_duration: int = 900) -> None:
        """Increment failed login attempts and lock if necessary"""
        self.failed_login_attempts += 1
        if self.failed_login_attempts >= max_attempts:
            self.locked_until = datetime.utcnow() + timedelta(seconds=lockout_duration)
    
    def verify_email(self) -> None:
        """Mark email as verified"""
        self.is_email_verified = True
        self.email_verification_token = None
        self.status = UserStatus.ACTIVE
        self.updated_at = datetime.utcnow()
    
    def activate(self) -> None:
        """Activate user account"""
        self.status = UserStatus.ACTIVE
        self.updated_at = datetime.utcnow()
    
    def deactivate(self) -> None:
        """Deactivate user account"""
        self.status = UserStatus.INACTIVE
        self.updated_at = datetime.utcnow()
    
    def suspend(self) -> None:
        """Suspend user account"""
        self.status = UserStatus.SUSPENDED
        self.updated_at = datetime.utcnow()
