# src/chitai/controllers/access.py

# Standard library
from typing import Annotated
import logging

# Third-party libraries
from litestar.security.jwt import OAuth2Login
from litestar import Controller, Response, get, post
from litestar.params import Body
from litestar.enums import RequestEncodingType
from litestar.status_codes import HTTP_409_CONFLICT, HTTP_401_UNAUTHORIZED
from litestar.exceptions import HTTPException, PermissionDeniedException
from advanced_alchemy.extensions.litestar.providers import create_service_dependencies
from advanced_alchemy.exceptions import DuplicateKeyError

# Local imports
from chitai.services.user import UserService
from chitai.schemas.user import UserCreate, UserLogin, UserRead
from chitai.database.models.user import User

logger = logging.getLogger(__name__)


class AccessController(Controller):
    """Controller for user authentication and access management."""

    path = "/access"
    dependencies = create_service_dependencies(UserService, key="users_service")

    @post("/signup")
    async def register(self, data: UserCreate, users_service: UserService) -> UserRead:
        """
        Register a new user account.

        Creates a new user with the provided credentials. Email addresses must be unique.

        Request Body:
            data: User registration data including email and password.

        Injected Dependencies:
            users_service: The user service for database operations.

        Returns:
            The created user account as a UserRead schema.

        Raises:
            HTTPException (409): If a user with the provided email already exists.
        """
        try:
            user = await users_service.create(data)
            return users_service.to_schema(user, schema_type=UserRead)

        except DuplicateKeyError:
            raise HTTPException(
                status_code=HTTP_409_CONFLICT,
                detail="A user with this email already exists",
            )

    @post("/login")
    async def login(
        self,
        data: Annotated[
            UserLogin,
            Body(title="OAuth2 Login", media_type=RequestEncodingType.URL_ENCODED),
        ],
        users_service: UserService,
    ) -> Response[OAuth2Login]:
        """
        Authenticate a user and generate an OAuth2 token.

        Verifies the provided credentials and returns an authentication token
        for subsequent authenticated requests.

        Request Body:
            data: Login credentials (email and password).

        Injected Dependencies:
            users_service: The user service for authentication.

        Returns:
            OAuth2 token and login information.

        Raises:
            HTTPException (401): If credentials are invalid or user not found.
        """

        try:
            user = await users_service.authenticate(data.email, data.password)
        except PermissionDeniedException:
            raise HTTPException(
                status_code=HTTP_401_UNAUTHORIZED, detail="Invalid email or password"
            )

        from chitai.app import oauth2_auth

        return oauth2_auth.login(
            identifier=data.email,
            token_extras={"user_id": user.id, "email": user.email},
        )

    @get("/me")
    async def get_user_info(self, current_user: User) -> UserRead:
        """
        Retrieve the currently authenticated user's information.

        Returns the profile information of the user making the request.

        Injected Dependencies:
            current_user: The authenticated user from the OAuth2 token.

        Returns:
            The current user's information as a UserRead schema.
        """

        return UserRead(**current_user.to_dict())
