from pathlib import Path
import uuid
from datetime import datetime
from fastapi import HTTPException, UploadFile, status
from sqlmodel import Session

from app.models.user import User, Role
from app.schemas.user import UserUpdate
from app.repositories.user_repo import UserRepository
from app.repositories.user_session_repo import UserSessionRepository
from app.core.security import hash_password, verify_password
from app.utils.image import validate_profile_image
from app.core.config import get_settings
from app.core.constants import (
    ERR_FORBIDDEN,
    ERR_OLD_PASSWORD,
    ERR_ADMINS_CAN_DELETE_ONLY_STANDARD_USERS,
    ERR_EMAIL_REGISTERED
)

settings = get_settings()

class UserService:
    """Service for user-specific operations."""

    @staticmethod
    def update_user(current_user: User, data: UserUpdate, session: Session) -> User:
        """Update profile fields on the current user."""
        for field, value in data.model_dump(exclude_unset=True).items():
            setattr(current_user, field, value)
        current_user.updated_at = datetime.utcnow()
        return UserRepository.update(session, current_user)

    @staticmethod
    def change_email(current_user: User, new_email: str, session: Session):
        """Change user's email address."""
        # 1. No-op check
        if current_user.email == new_email:
            return {"message": "Email unchanged"}
        # 2. Ensure email uniqueness
        existing = UserRepository.get_by_email(session, new_email)
        if existing:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=ERR_EMAIL_REGISTERED,
            )
        # 3. Update email
        current_user.email = new_email
        current_user.updated_at = datetime.utcnow()
        user = UserRepository.update(session, current_user)
        # 4. Revoke ALL sessions (critical)
        UserSessionRepository.revoke_all_for_user(session, user.id)
        return {"message": "Email updated successfully. Please log in again."}

    @staticmethod
    def update_profile_image(current_user: User, file: UploadFile, session: Session) -> User:
        """Validate and store profile image, update user's profile_image field."""
        validate_profile_image(file)
        # Use pathlib for handling paths
        profile_image_directory = Path(settings.PROFILE_IMAGE_DIRECTORY)
        # Ensure the directory exists
        profile_image_directory.mkdir(parents=True, exist_ok=True)
        # Create a unique name for the profile image
        unique_name = f"{uuid.uuid4().hex}_{file.filename}"
        # Define the full file path
        file_path = profile_image_directory / unique_name
        # Save the file to the defined path
        with open(file_path, "wb") as buffer:
            buffer.write(file.file.read())
        # Update the user's profile image and last update time
        current_user.profile_image = str(file_path)
        current_user.updated_at = datetime.utcnow()
        # Save the user with the updated profile image
        return UserRepository.update(session, current_user)

    @staticmethod
    def change_password(current_user: User, old_password: str, new_password: str, session: Session):
        """Change user's password after validating the old password."""
        # 1. Verify old password
        if not verify_password(old_password, current_user.hashed_password):
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=ERR_OLD_PASSWORD)
        # 2. Rotate password hash
        current_user.hashed_password = hash_password(new_password)
        current_user.updated_at = datetime.utcnow()
        # 3. Persist user update
        user = UserRepository.update(session, current_user)
        # 4. Revoke ALL active sessions
        UserSessionRepository.revoke_all_for_user(session, user.id)
        return {"message": "Password updated successfully. Please log in again."}

    @staticmethod
    def delete_user(current_user: User, target: User, session: Session) -> None:
        """Soft-delete a target user respecting role-based rules."""
        if current_user.role == Role.USERS:
            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERR_FORBIDDEN)
        if current_user.role == Role.ADMIN and target.role != Role.USERS:
            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERR_ADMINS_CAN_DELETE_ONLY_STANDARD_USERS)
        return UserRepository.soft_delete_user(session, target)
