"""
app/models/user.py
==================
User model per autenticazione multi-tenant.

Responsabilità:
- Hashing password con bcrypt
- Validazione password
- Serializzazione user per JWT token
"""

import bcrypt
from datetime import datetime


class User:
    """
    Modello User per gestione autenticazione.
    
    Attributi:
        id (int): ID univoco dell'utente
        id_tenant (int): Tenant a cui appartiene
        email (str): Email univoca per tenant
        nome (str): Nome completo
        password_hash (str): Hash bcrypt della password
        ruolo (str): 'admin_tenant', 'manager', 'operatore', 'visualizzazione'
        permessi (dict): JSON permessi specifici
        data_creazione (datetime): Timestamp creazione
        ultimo_accesso (datetime): Timestamp ultimo login
    """
    
    def __init__(self, id, id_tenant, email, nome, password_hash, ruolo='operatore', 
                 permessi=None, data_creazione=None, ultimo_accesso=None):
        self.id = id
        self.id_tenant = id_tenant
        self.email = email
        self.nome = nome
        self.password_hash = password_hash
        self.ruolo = ruolo
        self.permessi = permessi or {}
        self.data_creazione = data_creazione or datetime.utcnow()
        self.ultimo_accesso = ultimo_accesso
    
    @staticmethod
    def hash_password(password: str) -> str:
        """
        Hash password con bcrypt.
        
        Args:
            password (str): Password in chiaro
            
        Returns:
            str: Hash bcrypt della password
            
        Esempio:
            >>> pwd_hash = User.hash_password("miaPassword123")
            >>> # pwd_hash è una stringa sicura da salvare nel database
        """
        salt = bcrypt.gensalt(rounds=12)
        return bcrypt.hashpw(password.encode('utf-8'), salt).decode('utf-8')
    
    def verify_password(self, password: str) -> bool:
        """
        Verifica password in chiaro contro l'hash salvato.
        
        Args:
            password (str): Password in chiaro da verificare
            
        Returns:
            bool: True se password corretta, False altrimenti
            
        Esempio:
            >>> user = User(..., password_hash=hash)
            >>> if user.verify_password("miaPassword123"):
            ...     print("Login OK")
        """
        try:
            return bcrypt.checkpw(password.encode('utf-8'), self.password_hash.encode('utf-8'))
        except Exception:
            return False
    
    def to_dict(self, include_password=False):
        """
        Serializza user a dict (per API response).
        
        Args:
            include_password (bool): Se includere password_hash (default: False per sicurezza)
            
        Returns:
            dict: Dati user serializzati
            
        Esempio:
            >>> user.to_dict()
            {
                'id': 1,
                'email': 'operatore@studium.it',
                'nome': 'Operatore Demo',
                'ruolo': 'operatore',
                'id_tenant': 1
            }
        """
        data = {
            'id': self.id,
            'email': self.email,
            'nome': self.nome,
            'ruolo': self.ruolo,
            'id_tenant': self.id_tenant,
            'permessi': self.permessi,
            'data_creazione': self.data_creazione.isoformat() if self.data_creazione else None,
            'ultimo_accesso': self.ultimo_accesso.isoformat() if self.ultimo_accesso else None,
        }
        
        if include_password:
            data['password_hash'] = self.password_hash
            
        return data

    def to_jwt_payload(self):
        """
        Crea payload per JWT token (cosa mettiamo dentro il token).

        Returns:
            dict: Payload con dati essenziali per validazione

        Nota: JWT deve essere leggero, quindi includiamo solo dati critici:
        - user_id: per identificare l'utente
        - email: per log/audit
        - tenant_id: CRITICO per isolamento multi-tenant
        - ruolo: per autorizzazione (admin vs operatore)
        """
        return {
            'user_id': self.id,
            'email': self.email,
            'tenant_id': self.id_tenant,
            'ruolo': self.ruolo,
            'permessi': self.permessi,
        }

    @staticmethod
    def from_dict(data):
        """
        Factory method: crea User da dict (es. da database).

        Args:
            data (dict): Dict con campi user

        Returns:
            User: Istanza User
        """
        return User(
            id=data.get('id'),
            id_tenant=data.get('id_tenant'),
            email=data.get('email'),
            nome=data.get('nome'),
            password_hash=data.get('password_hash'),
            ruolo=data.get('ruolo', 'operatore'),
            permessi=data.get('permessi', {}),
            data_creazione=data.get('data_creazione'),
            ultimo_accesso=data.get('ultimo_accesso'),
        )

    def __repr__(self):
        return f"<User {self.email} (tenant={self.id_tenant}, ruolo={self.ruolo})>"

