from __future__ import annotations

from typing import TYPE_CHECKING

from fortytwo.parameter import Parameter, with_pagination
from fortytwo.resources.user.parameter import UserParameters
from fortytwo.resources.user.resource import (
    GetMe,
    GetUserById,
    GetUsers,
    GetUsersByAccreditationId,
    GetUsersByAchievementId,
    GetUsersByCampusId,
    GetUsersByCoalitionId,
    GetUsersByCursusId,
    GetUsersByDashId,
    GetUsersByEventId,
    GetUsersByExpertiseId,
    GetUsersByGroupId,
    GetUsersByPartnershipId,
    GetUsersByProjectId,
    GetUsersByQuestId,
    GetUsersByTeamId,
    GetUsersByTitleId,
)


if TYPE_CHECKING:
    from fortytwo.core import ApiListResponse, ApiResponse, AsyncClient
    from fortytwo.resources.user.user import User


class AsyncUserManager:
    """
    Asynchronous manager for user-related API operations.
    """

    parameters = UserParameters

    def __init__(self, client: AsyncClient) -> None:
        self.__client = client

    async def get_me(self, *params: Parameter) -> ApiResponse[User]:
        """
        Get the authenticated user's information.

        Args:
            *params: Additional request parameters

        Returns:
            User object

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetMe(), *params)

    async def get_by_id(self, user_id: int, *params: Parameter) -> ApiResponse[User]:
        """
        Get a user by ID.

        Args:
            user_id: The user ID to fetch
            *params: Additional request parameters

        Returns:
            User object

        Raises:
            FortyTwoNotFoundException: If user is not found
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUserById(user_id), *params)

    @with_pagination
    async def get_all(
        self,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get all users.

        Args:
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsers(), *params)

    @with_pagination
    async def get_by_coalition_id(
        self,
        coalition_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by coalition ID.

        Args:
            coalition_id: The coalition ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByCoalitionId(coalition_id), *params)

    @with_pagination
    async def get_by_dash_id(
        self,
        dash_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by dash ID.

        Args:
            dash_id: The dash ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByDashId(dash_id), *params)

    @with_pagination
    async def get_by_event_id(
        self,
        event_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by event ID.

        Args:
            event_id: The event ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByEventId(event_id), *params)

    @with_pagination
    async def get_by_accreditation_id(
        self,
        accreditation_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by accreditation ID.

        Args:
            accreditation_id: The accreditation ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByAccreditationId(accreditation_id), *params)

    @with_pagination
    async def get_by_team_id(
        self,
        team_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by team ID.

        Args:
            team_id: The team ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByTeamId(team_id), *params)

    @with_pagination
    async def get_by_project_id(
        self,
        project_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by project ID.

        Args:
            project_id: The project ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByProjectId(project_id), *params)

    @with_pagination
    async def get_by_partnership_id(
        self,
        partnership_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by partnership ID.

        Args:
            partnership_id: The partnership ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByPartnershipId(partnership_id), *params)

    @with_pagination
    async def get_by_expertise_id(
        self,
        expertise_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by expertise ID.

        Args:
            expertise_id: The expertise ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByExpertiseId(expertise_id), *params)

    @with_pagination
    async def get_by_cursus_id(
        self,
        cursus_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by cursus ID.

        Args:
            cursus_id: The cursus ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByCursusId(cursus_id), *params)

    @with_pagination
    async def get_by_campus_id(
        self,
        campus_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by campus ID.

        Args:
            campus_id: The campus ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByCampusId(campus_id), *params)

    @with_pagination
    async def get_by_achievement_id(
        self,
        achievement_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by achievement ID.

        Args:
            achievement_id: The achievement ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByAchievementId(achievement_id), *params)

    @with_pagination
    async def get_by_title_id(
        self,
        title_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by title ID.

        Args:
            title_id: The title ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByTitleId(title_id), *params)

    @with_pagination
    async def get_by_quest_id(
        self,
        quest_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by quest ID.

        Args:
            quest_id: The quest ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByQuestId(quest_id), *params)

    @with_pagination
    async def get_by_group_id(
        self,
        group_id: int,
        *params: Parameter,
        page: int | None = None,
        page_size: int | None = None,
    ) -> ApiListResponse[User]:
        """
        Get users by group ID.

        Args:
            group_id: The group ID whose users to fetch
            *params: Additional request parameters
            page: Page number to fetch (1-indexed)
            page_size: Number of items per page (1-100)

        Returns:
            List of User objects

        Raises:
            FortyTwoRequestException: If the request fails
        """
        return await self.__client.request(GetUsersByGroupId(group_id), *params)
