"""
User Model mit RBAC
"""
from enum import Enum
from sqlalchemy import Column, Integer, String, Enum as SQLEnum, Boolean, DateTime, Text
from sqlalchemy.orm import relationship
from app.models.base import Base, TimestampMixin


class UserRole(str, Enum):
    """User roles for RBAC"""
    ADMIN = "admin"
    EDITOR = "editor"
    READONLY = "readonly"


class AuthProvider(str, Enum):
    """Authentication provider that owns this user identity.

    `local`  = username/password in users.password_hash
    `ldap`   = LDAPS-bound to enterprise directory
    `saml`   = SAML 2.0 SSO via configured IdP
    `oidc`   = OAuth 2.0 / OIDC SSO via configured IdP

    Used by AuthOrchestrator to route credential checks and by JIT
    provisioning to remember origin of an auto-created stub.
    """
    LOCAL = "local"
    LDAP = "ldap"
    SAML = "saml"
    OIDC = "oidc"


class User(Base, TimestampMixin):
    """
    User-Tabelle für Authentifizierung und Autorisierung

    Sicherheitsfeatures:
    - bcrypt Password-Hashing (via passlib)
    - Account Lockout nach fehlgeschlagenen Login-Versuchen
    - Email-Verifizierung (optional)
    """
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    username = Column(String(50), unique=True, nullable=False, index=True)
    email = Column(String(255), unique=True, nullable=False, index=True)
    # Nullable for external (LDAP/SSO) users that have no local password
    password_hash = Column(String(255), nullable=True)

    # RBAC
    role = Column(
        SQLEnum(UserRole),
        default=UserRole.READONLY,
        nullable=False,
        index=True
    )

    # Auth provider (which strategy owns this identity).
    # values_callable forces SQLAlchemy to use the Python enum *values* (lowercase
    # 'local', 'ldap', ...) rather than the default *names* (LOCAL, LDAP, ...) when
    # talking to Postgres. Required because migration 009 created the postgres
    # `authprovider` type with the lowercase values.
    auth_provider = Column(
        SQLEnum(
            AuthProvider,
            name="authprovider",
            values_callable=lambda x: [e.value for e in x],
        ),
        default=AuthProvider.LOCAL,
        nullable=False,
        index=True,
    )
    external_id = Column(String(255), nullable=True, index=True)  # IdP subject / objectGUID
    external_groups = Column(Text, nullable=True)                  # JSON array of group names/IDs
    last_provider_sync = Column(DateTime, nullable=True)

    # MFA: TOTP (RFC 6238). Only meaningful for auth_provider=LOCAL;
    # SSO users get MFA from their IdP.
    totp_secret = Column(String(255), nullable=True)  # base32, encrypted at rest
    totp_enabled = Column(Boolean, default=False, nullable=False)

    # Account Status
    is_active = Column(Boolean, default=True, nullable=False)
    is_verified = Column(Boolean, default=False, nullable=False)
    failed_login_attempts = Column(Integer, default=0, nullable=False)

    # Relationships
    audit_logs = relationship("AuditLog", back_populates="user", cascade="all, delete-orphan")
    
    @staticmethod
    def _get_user_groups_table():
        from app.models.group import user_groups
        return user_groups
        
    groups = relationship("Group", secondary="user_groups", back_populates="users", lazy="selectin")

    def __repr__(self):
        return f"<User(username='{self.username}', role='{self.role}')>"

    def has_permission(self, required_role: UserRole) -> bool:
        """
        Prüft, ob User die erforderliche Berechtigung hat

        Hierarchie: ADMIN > EDITOR > READONLY
        """
        role_hierarchy = {
            UserRole.READONLY: 0,
            UserRole.EDITOR: 1,
            UserRole.ADMIN: 2
        }
        return role_hierarchy[self.role] >= role_hierarchy[required_role]
