"""
User management and authentication models.
"""

from datetime import datetime, timezone
from enum import Enum
from typing import Optional

from sqlalchemy import Column, DateTime, Enum as SQLEnum, Integer, String, Boolean, Text

from ..database import Base


class UserRole(str, Enum):
    """User access roles."""
    OPERATOR = "operator"      # Basic machine operation
    SUPERVISOR = "supervisor"  # Recipe management, advanced operations
    TECHNICIAN = "technician"  # Maintenance, diagnostics, configuration
    ADMIN = "admin"           # Full system access


class User(Base):
    """
    User account for system access and audit trail.
    Based on the original Users.csv structure.
    """
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    
    # User identification
    username = Column(String(50), nullable=False, unique=True, index=True, comment="Unique username")
    email = Column(String(100), nullable=True, unique=True, index=True, comment="User email address")
    full_name = Column(String(100), nullable=True, comment="User full name")
    
    # Authentication
    password_hash = Column(String(255), nullable=False, comment="Hashed password")
    salt = Column(String(50), nullable=True, comment="Password salt")
    
    # Authorization
    role = Column(SQLEnum(UserRole), nullable=False, default=UserRole.OPERATOR, index=True)
    permissions = Column(Text, nullable=True, comment="Additional permissions (JSON)")
    
    # Account status
    is_active = Column(Boolean, nullable=False, default=True, comment="Account is active")
    is_locked = Column(Boolean, nullable=False, default=False, comment="Account is locked")
    failed_login_attempts = Column(Integer, nullable=False, default=0, comment="Failed login count")
    
    # Timestamps
    created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
    last_login = Column(DateTime(timezone=True), nullable=True, comment="Last successful login")
    last_login_attempt = Column(DateTime(timezone=True), nullable=True, comment="Last login attempt")
    password_changed_at = Column(DateTime(timezone=True), nullable=True, comment="Last password change")
    
    # Profile information
    phone = Column(String(20), nullable=True, comment="Phone number")
    department = Column(String(50), nullable=True, comment="Department or team")
    shift = Column(String(20), nullable=True, comment="Work shift")
    badge_number = Column(String(20), nullable=True, comment="Employee badge number")
    
    # Preferences
    language = Column(String(5), nullable=False, default="en", comment="Preferred language")
    timezone = Column(String(50), nullable=False, default="UTC", comment="User timezone")
    
    # Security
    require_password_change = Column(Boolean, nullable=False, default=False, comment="Force password change on next login")
    session_timeout = Column(Integer, nullable=False, default=3600, comment="Session timeout in seconds")

    def __repr__(self) -> str:
        return f"<User(id={self.id}, username='{self.username}', role='{self.role}', active={self.is_active})>"
    
    def has_permission(self, required_role: UserRole) -> bool:
        """Check if user has required permission level."""
        role_hierarchy = {
            UserRole.OPERATOR: 1,
            UserRole.SUPERVISOR: 2,
            UserRole.TECHNICIAN: 3,
            UserRole.ADMIN: 4
        }
        
        return role_hierarchy.get(self.role, 0) >= role_hierarchy.get(required_role, 0)
    
    def can_manage_recipes(self) -> bool:
        """Check if user can create/edit recipes."""
        return self.has_permission(UserRole.SUPERVISOR)
    
    def can_access_diagnostics(self) -> bool:
        """Check if user can access diagnostic features."""
        return self.has_permission(UserRole.TECHNICIAN)
    
    def can_modify_system_config(self) -> bool:
        """Check if user can modify system configuration."""
        return self.has_permission(UserRole.ADMIN)
    
    def is_session_expired(self, last_activity: datetime) -> bool:
        """Check if user session has expired."""
        if not self.is_active or self.is_locked:
            return True
        
        time_since_activity = (datetime.now(timezone.utc) - last_activity).total_seconds()
        return time_since_activity > self.session_timeout
    
    def record_login_attempt(self, success: bool) -> None:
        """Record login attempt and update counters."""
        self.last_login_attempt = datetime.now(timezone.utc)
        
        if success:
            self.last_login = self.last_login_attempt
            self.failed_login_attempts = 0
            if self.is_locked:
                self.is_locked = False
        else:
            self.failed_login_attempts += 1
            # Lock account after 5 failed attempts
            if self.failed_login_attempts >= 5:
                self.is_locked = True
    
    def to_dict(self, include_sensitive: bool = False) -> dict:
        """Convert user to dictionary, optionally including sensitive data."""
        user_data = {
            "id": self.id,
            "username": self.username,
            "email": self.email,
            "full_name": self.full_name,
            "role": self.role.value if self.role else None,
            "is_active": self.is_active,
            "is_locked": self.is_locked,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "last_login": self.last_login.isoformat() if self.last_login else None,
            "phone": self.phone,
            "department": self.department,
            "shift": self.shift,
            "badge_number": self.badge_number,
            "language": self.language,
            "timezone": self.timezone,
        }
        
        if include_sensitive:
            user_data.update({
                "failed_login_attempts": self.failed_login_attempts,
                "last_login_attempt": self.last_login_attempt.isoformat() if self.last_login_attempt else None,
                "password_changed_at": self.password_changed_at.isoformat() if self.password_changed_at else None,
                "require_password_change": self.require_password_change,
                "session_timeout": self.session_timeout,
            })
        
        return user_data
    
    @classmethod
    def from_csv_row(cls, row: dict) -> "User":
        """Create User from CSV row data (migration utility)."""
        return cls(
            id=int(row.get("ID", 0)),
            username=row.get("Username", "unknown"),
            full_name=row.get("Name", ""),
            email=row.get("Email", ""),
            role=UserRole(row.get("Role", "operator").lower()),
            phone=row.get("Phone", ""),
            department=row.get("Department", ""),
            badge_number=row.get("BadgeNumber", ""),
            # Note: password will need to be set separately for security
            password_hash="MIGRATION_REQUIRED",
        )