from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from pydantic import BaseModel, EmailStr from typing import Optional import logging from datetime import datetime from app.db.session import get_db from app.models.user import User from app.utils.auth import get_current_user, get_password_hash, verify_password logger = logging.getLogger(__name__) router = APIRouter() class ProfileResponse(BaseModel): id: int email: str first_name: Optional[str] last_name: Optional[str] phone: Optional[str] bio: Optional[str] preferred_language: str timezone: str created_at: str updated_at: str class Config: orm_mode = True class ProfileUpdate(BaseModel): first_name: Optional[str] = None last_name: Optional[str] = None phone: Optional[str] = None bio: Optional[str] = None preferred_language: Optional[str] = None timezone: Optional[str] = None class PasswordUpdate(BaseModel): current_password: str new_password: str class EmailUpdate(BaseModel): new_email: EmailStr password: str @router.get("/", response_model=ProfileResponse) async def get_profile( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): logger.info(f"Profile requested for user: {current_user.email}") return ProfileResponse( id=current_user.id, email=current_user.email, first_name=current_user.first_name, last_name=current_user.last_name, phone=current_user.phone, bio=current_user.bio, preferred_language=current_user.preferred_language or "en", timezone=current_user.timezone or "UTC", created_at=str(current_user.created_at), updated_at=str(current_user.updated_at) if hasattr(current_user, 'updated_at') and current_user.updated_at else str(current_user.created_at) ) @router.put("/", response_model=ProfileResponse) async def update_profile( profile_data: ProfileUpdate, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): try: logger.info(f"Profile update requested for user: {current_user.email}") # Update only provided fields if profile_data.first_name is not None: current_user.first_name = profile_data.first_name if profile_data.last_name is not None: current_user.last_name = profile_data.last_name if profile_data.phone is not None: current_user.phone = profile_data.phone if profile_data.bio is not None: current_user.bio = profile_data.bio if profile_data.preferred_language is not None: current_user.preferred_language = profile_data.preferred_language if profile_data.timezone is not None: current_user.timezone = profile_data.timezone # Update the timestamp manually current_user.updated_at = datetime.utcnow() db.commit() db.refresh(current_user) logger.info(f"Profile updated successfully for user: {current_user.email}") return ProfileResponse( id=current_user.id, email=current_user.email, first_name=current_user.first_name, last_name=current_user.last_name, phone=current_user.phone, bio=current_user.bio, preferred_language=current_user.preferred_language or "en", timezone=current_user.timezone or "UTC", created_at=str(current_user.created_at), updated_at=str(current_user.updated_at) if hasattr(current_user, 'updated_at') and current_user.updated_at else str(current_user.created_at) ) except Exception as e: logger.error(f"Profile update error for {current_user.email}: {str(e)}") db.rollback() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error during profile update" ) @router.put("/password") async def update_password( password_data: PasswordUpdate, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): try: logger.info(f"Password update requested for user: {current_user.email}") # Verify current password if not verify_password(password_data.current_password, current_user.password_hash): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Current password is incorrect" ) # Validate new password if len(password_data.new_password) < 6: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="New password must be at least 6 characters long" ) # Update password current_user.password_hash = get_password_hash(password_data.new_password) current_user.updated_at = datetime.utcnow() db.commit() logger.info(f"Password updated successfully for user: {current_user.email}") return {"message": "Password updated successfully"} except HTTPException: raise except Exception as e: logger.error(f"Password update error for {current_user.email}: {str(e)}") db.rollback() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error during password update" ) @router.put("/email") async def update_email( email_data: EmailUpdate, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): try: logger.info(f"Email update requested for user: {current_user.email}") # Verify password if not verify_password(email_data.password, current_user.password_hash): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Password is incorrect" ) # Check if new email is already taken existing_user = db.query(User).filter(User.email == email_data.new_email).first() if existing_user and existing_user.id != current_user.id: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered" ) old_email = current_user.email current_user.email = email_data.new_email current_user.updated_at = datetime.utcnow() db.commit() logger.info(f"Email updated successfully from {old_email} to {email_data.new_email}") return {"message": "Email updated successfully"} except HTTPException: raise except Exception as e: logger.error(f"Email update error for {current_user.email}: {str(e)}") db.rollback() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error during email update" ) @router.delete("/") async def delete_account( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): try: logger.info(f"Account deletion requested for user: {current_user.email}") # Note: In a production environment, you might want to: # 1. Soft delete instead of hard delete # 2. Clean up related data (videos, transcriptions, etc.) # 3. Add confirmation mechanisms user_email = current_user.email db.delete(current_user) db.commit() logger.info(f"Account deleted successfully for user: {user_email}") return {"message": "Account deleted successfully"} except Exception as e: logger.error(f"Account deletion error for {current_user.email}: {str(e)}") db.rollback() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error during account deletion" )