"""Authentication router - login, logout, profile.""" from fastapi import APIRouter, Depends, HTTPException, Request, status from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from src.backend.database import get_db from src.backend.api.middleware.api_key import get_current_user from src.backend.models.orm.user import User from src.backend.models.api.user import ( LoginRequest, LoginResponse, PinLoginRequest, PinUserItem, UserProfileUpdate, UserResponse, ) from src.backend.services.auth_service import ( authenticate_pin, authenticate_user, login_user, logout_user, ) router = APIRouter(prefix="/api/auth", tags=["auth"]) @router.post("/login", response_model=LoginResponse) async def login(data: LoginRequest, db: AsyncSession = Depends(get_db)): """Login with username and password, receive API key.""" user = await authenticate_user(db, data.username, data.password) if user is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid username or password", ) api_key = await login_user(db, user) return LoginResponse( user=UserResponse.model_validate(user), api_key=api_key, ) @router.get("/pin-users", response_model=list[PinUserItem]) async def pin_users(db: AsyncSession = Depends(get_db)): """Utenti che possono entrare con PIN (#59): attivi, non admin, con PIN. Pubblico per costruzione (serve prima del login): espone solo id e nome. """ result = await db.execute( select(User).where( User.active == True, # noqa: E712 User.is_admin == False, # noqa: E712 User.pin_hash.is_not(None), ) ) items = [ PinUserItem(id=u.id, display_name=u.display_name or u.username) for u in result.scalars().all() ] items.sort(key=lambda i: i.display_name.casefold()) return items @router.post("/login-pin", response_model=LoginResponse) async def login_pin(data: PinLoginRequest, db: AsyncSession = Depends(get_db)): """Login con user_id e PIN a 4 cifre (#59); stessa risposta del login.""" user = await authenticate_pin(db, data.user_id, data.pin) api_key = await login_user(db, user) return LoginResponse(user=UserResponse.model_validate(user), api_key=api_key) @router.post("/logout", status_code=status.HTTP_204_NO_CONTENT) async def logout( request: Request, all_sessions: bool = False, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """Logout. Deletes this session's API key only; ?all_sessions=true deletes every key of the user.""" await logout_user( db, user, key=request.headers.get("X-API-Key"), all_sessions=all_sessions ) @router.get("/me", response_model=UserResponse) async def get_profile(user: User = Depends(get_current_user)): """Get current user profile.""" return UserResponse.model_validate(user) @router.put("/me", response_model=UserResponse) async def update_profile( data: UserProfileUpdate, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """Update own profile (display_name, language, theme).""" update_data = data.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(user, field, value) await db.flush() await db.refresh(user) return UserResponse.model_validate(user)