# src/chitai/services/user.py

# Standard library
import logging

# Third-party library
from advanced_alchemy.service import SQLAlchemyAsyncRepositoryService
from advanced_alchemy.repository import SQLAlchemyAsyncRepository
from litestar.exceptions import PermissionDeniedException
from litestar.security.jwt import Token

# Local imports
from chitai.database.models.user import User

logger = logging.getLogger(__name__)


class UserService(SQLAlchemyAsyncRepositoryService[User]):
    """User service for managing user operations."""

    class Repo(SQLAlchemyAsyncRepository[User]):
        model_type = User

    repository_type = Repo

    async def authenticate(self, email: str, password: str) -> User:
        """
        Authenticate a user by email and password.

        Verifies that the user exists and the provided password matches their argon2 hash.

        Args:
            email: The user's email address.
            password: The plain text password to verify.

        Returns:
            The authenticated User entity.

        Raises:
            PermissionDeniedException: If the user does not exist or password is invalid.
                                      Uses generic message to prevent user enumeration.
        """

        user = await self.get_one_or_none(email=email)

        if not user or not user.password.verify(password):
            logger.warning(f"Login failed for: {email}")
            raise PermissionDeniedException("User not found or password invalid.")

        return user

    async def get_user_by_token(self, token: Token) -> User:
        """
        Retrieve a user by their authentication token.

        Assumes the token has already been validated and decoded by the OAuth2 middleware.
        This function only fetches the corresponding user from the database using the
        email from the token's 'sub' claim.

        Args:
            token: The decoded authentication token (pre-validated by OAuth2 middleware)
                    containing the user's email in the 'sub' claim.

        Returns:
            The User entity associated with the token.

        Raises:
            PermissionDeniedException: If no user exists for the email in the token,
                                        or if the user account is inactive.
        """
        user = await self.get_one_or_none(email=token.sub)

        if not user:
            raise PermissionDeniedException("Invalid token.")

        return user
