"""
Authentication Pydantic Models pentru ROA2WEB

Acest modul definește toate modelele de date folosite în sistemul de autentificare,
incluzând request/response models și modele pentru user data.

Modelele acoperă:
- Login request și response
- Token data și management
- User information și permisiuni
- Company access control
"""

from pydantic import BaseModel, Field, validator, EmailStr
from typing import List, Optional, Dict, Any
from datetime import datetime
from enum import Enum


class PermissionType(str, Enum):
    """Tipurile de permisiuni disponibile în sistem"""
    READ = "read"
    WRITE = "write"
    DELETE = "delete"
    ADMIN = "admin"
    REPORTS = "reports"
    EXPORT = "export"


class TokenType(str, Enum):
    """Tipurile de token-uri JWT"""
    ACCESS = "access"
    REFRESH = "refresh"


class LoginRequest(BaseModel):
    """Model pentru request-ul de login"""
    username: str = Field(
        ..., 
        min_length=3, 
        max_length=50,
        description="Numele utilizatorului",
        example="admin"
    )
    password: str = Field(
        ..., 
        min_length=1,
        description="Parola utilizatorului"
    )
    remember_me: bool = Field(
        default=False,
        description="Dacă să păstreze utilizatorul autentificat mai mult timp"
    )

    @validator('username')
    def username_alphanumeric(cls, v):
        """Validează că username-ul conține doar caractere permise (inclusiv spații)"""
        # Permitem litere, cifre, spații, _, și -
        allowed_chars = v.replace(' ', '').replace('_', '').replace('-', '')
        if not allowed_chars.isalnum():
            raise ValueError('Username-ul poate conține doar litere, cifre, spații, _ și -')
        return v.upper()  # Convertim la uppercase pentru consistență cu Oracle


class TokenResponse(BaseModel):
    """Model pentru răspunsul de autentificare cu token-uri"""
    access_token: str = Field(description="JWT access token")
    refresh_token: Optional[str] = Field(
        default=None, 
        description="JWT refresh token (opțional)"
    )
    token_type: str = Field(
        default="bearer", 
        description="Tipul token-ului (întotdeauna 'bearer')"
    )
    expires_in: int = Field(
        description="Timpul de expirare al access token-ului în secunde"
    )
    user: 'CurrentUser' = Field(description="Informațiile utilizatorului autentificat")


class RefreshTokenRequest(BaseModel):
    """Model pentru request-ul de refresh token"""
    refresh_token: str = Field(description="Refresh token-ul valid")


class LogoutRequest(BaseModel):
    """Model pentru request-ul de logout"""
    refresh_token: Optional[str] = Field(
        default=None,
        description="Refresh token de invalidat (opțional)"
    )


class CurrentUser(BaseModel):
    """Model pentru utilizatorul curent autentificat"""
    username: str = Field(description="Numele utilizatorului")
    user_id: Optional[int] = Field(
        default=None,
        description="ID-ul utilizatorului în baza de date"
    )
    email: Optional[EmailStr] = Field(
        default=None,
        description="Email-ul utilizatorului"
    )
    companies: List[str] = Field(
        default_factory=list,
        description="Lista codurilor firmelor la care utilizatorul are acces"
    )
    permissions: List[PermissionType] = Field(
        default_factory=lambda: [PermissionType.READ],
        description="Lista permisiunilor utilizatorului"
    )
    is_active: bool = Field(
        default=True,
        description="Dacă utilizatorul este activ"
    )
    last_login: Optional[datetime] = Field(
        default=None,
        description="Data ultimei autentificări"
    )

    @validator('companies')
    def companies_not_empty_if_active(cls, v, values):
        """Validează că utilizatorii activi au cel puțin o firmă"""
        if values.get('is_active', True) and not v:
            raise ValueError('Utilizatorii activi trebuie să aibă acces la cel puțin o firmă')
        return v


class UserCompany(BaseModel):
    """Model pentru o firmă la care utilizatorul are acces"""
    code: str = Field(description="Codul firmei (schema Oracle)")
    name: Optional[str] = Field(
        default=None,
        description="Numele firmei (dacă este disponibil)"
    )
    permissions: List[PermissionType] = Field(
        default_factory=lambda: [PermissionType.READ],
        description="Permisiunile utilizatorului pentru această firmă"
    )
    is_default: bool = Field(
        default=False,
        description="Dacă aceasta este firma implicită pentru utilizator"
    )


class CompanyAccessRequest(BaseModel):
    """Model pentru verificarea accesului la o firmă"""
    company_code: str = Field(description="Codul firmei de verificat")
    required_permissions: Optional[List[PermissionType]] = Field(
        default=None,
        description="Permisiunile necesare (opțional)"
    )


class CompanyAccessResponse(BaseModel):
    """Model pentru răspunsul de verificare acces firmă"""
    has_access: bool = Field(description="Dacă utilizatorul are acces")
    company: Optional[UserCompany] = Field(
        default=None,
        description="Detaliile firmei dacă utilizatorul are acces"
    )
    missing_permissions: Optional[List[PermissionType]] = Field(
        default=None,
        description="Permisiunile lipsă (dacă aplicabil)"
    )


class AuthError(BaseModel):
    """Model pentru erorile de autentificare"""
    error: str = Field(description="Tipul erorii")
    error_description: str = Field(description="Descrierea detaliată a erorii")
    error_code: Optional[str] = Field(
        default=None,
        description="Codul de eroare pentru procesare automată"
    )


class AuthStats(BaseModel):
    """Model pentru statisticile de autentificare"""
    total_users: int = Field(description="Numărul total de utilizatori")
    active_sessions: int = Field(description="Sesiuni active curente")
    cache_hit_ratio: float = Field(
        description="Rata de hit a cache-ului pentru date utilizatori"
    )
    last_cleanup: Optional[datetime] = Field(
        default=None,
        description="Ultima curățare a cache-ului"
    )


class PasswordChangeRequest(BaseModel):
    """Model pentru schimbarea parolei (pentru viitor)"""
    current_password: str = Field(description="Parola curentă")
    new_password: str = Field(
        min_length=8,
        description="Noua parolă (minim 8 caractere)"
    )
    confirm_password: str = Field(description="Confirmarea noii parole")

    @validator('confirm_password')
    def passwords_match(cls, v, values):
        """Validează că parolele coincid"""
        if 'new_password' in values and v != values['new_password']:
            raise ValueError('Parolele nu coincid')
        return v


class SessionInfo(BaseModel):
    """Model pentru informațiile despre sesiune"""
    session_id: str = Field(description="ID-ul sesiunii")
    username: str = Field(description="Numele utilizatorului")
    created_at: datetime = Field(description="Data creării sesiunii")
    last_activity: datetime = Field(description="Ultima activitate")
    ip_address: Optional[str] = Field(
        default=None,
        description="Adresa IP a utilizatorului"
    )
    user_agent: Optional[str] = Field(
        default=None,
        description="User agent-ul browserului"
    )
    is_active: bool = Field(
        default=True,
        description="Dacă sesiunea este încă activă"
    )


# Update la forward references pentru TokenResponse
TokenResponse.model_rebuild()