# AUTOGENERATED! DO NOT EDIT! File to edit: notebooks/API_User.ipynb (unless otherwise specified).

__all__ = ["User"]

# Cell

from typing import *

# Internal Cell

import os

import pandas as pd
from fastcore.foundation import patch

from ..logger import get_logger, set_level
from ..helper import (
    get_data,
    post_data,
    delete_data,
    generate_df,
    get_attributes_from_instances,
)

from .client import Client

# Internal Cell

logger = get_logger(__name__)

# Cell


class User:
    """A class for managing users in the server.

    !!! info

        Except for the `update` method, all other methods are accessible only to the super user.
    """

    USER_COLS = [
        "id",
        "username",
        "super_user",
        "disabled",
        "created",
        "subscription_type",
        "first_name",
        "last_name",
        "email",
    ]

    def __init__(
        self,
        id: int,
        username: Optional[str] = None,
        first_name: Optional[str] = None,
        last_name: Optional[str] = None,
        email: Optional[str] = None,
        subscription_type: Optional[str] = None,
        super_user: Optional[bool] = None,
        disabled: Optional[str] = None,
        created: Optional[str] = None,
    ):
        """Constructs a new User instance.

        Args:
            id: User id.
            username: The username of the user.
            first_name: The first name of the user.
            last_name: The last name of the user.
            email: The email address of the user.
            subscription_type: User subscription type. Currently, the API supports only the following subscription
                types **small**, **medium** and **large**.
            super_user: Flag to indicate the user type.
            disabled: Flag to indicate the status of the user.
            created: User creation date.
        """

        self.id = id
        self.username = username
        self.first_name = first_name
        self.last_name = last_name
        self.email = email
        self.subscription_type = subscription_type
        self.super_user = super_user
        self.disabled = disabled
        self.created = created

    @staticmethod
    def create(
        *,
        username: str,
        first_name: str,
        last_name: str,
        email: str,
        password: str,
        subscription_type: str,
        super_user: bool = False,
    ) -> pd.DataFrame:
        """Create a new user in the server.

        Args:
            username: The username for the new user.
            first_name: The first name for the new user.
            last_name: The last name for the new user.
            email: The email for the new user.
            password: The password for the new user.
            subscription_type: User subscription type. Currently, the API supports only the following subscription
                types **small**, **medium** and **large**.
            super_user: If set to **True**, then the new user will have super user privilages.
                If **None**, then the default value **False** will be used to create a non-super user.

        Returns:
                A pandas DataFrame encapsulating the details of the newly created user.

        Raises:
            ConnectionError: If the server address is invalid or not reachable.
            ValueError: If the username or email is already present in the server.

        An example to create a new user:

        ```python
            new_user = User.create(
                username="example_username",
                first_name="example_first_name",
                last_name="example_last_name",
                email="example@example.com",
                password="example_password",
            )
        ```
        """
        req_data = dict(
            username=username,
            first_name=first_name,
            last_name=last_name,
            email=email,
            subscription_type=subscription_type,
            super_user=super_user,
            password=password,
        )

        response = Client._post_data(relative_url=f"/user/", data=req_data)

        return pd.DataFrame(response, index=[0])[User.USER_COLS]

    @staticmethod
    def ls(
        offset: int = 0,
        limit: int = 100,
        disabled: bool = False,
    ) -> pd.DataFrame:
        """Return the list of User instances available in the server.

        Args:
            offset: The number of users to offset at the beginning. If **None**, then the default value **0** will be used.
            limit: The maximum number of users to return from the server. If None, then the default value 100 will be used.
            disabled: If set to **True**, then only the deleted users will be returned. Else, the default value **False** will
                be used to return only the list of active users.

        Returns:
            A list of User instances available in the server.

        Raises:
            ConnectionError: If the server address is invalid or not reachable.

        An example to get the user's list from the server:

        ```python
        User.ls()
        ```
        """
        users = Client._get_data(
            relative_url=f"/user/?disabled={disabled}&offset={offset}&limit={limit}"
        )

        ux = [
            User(
                id=user["id"],
                username=user["username"],
                first_name=user["first_name"],
                last_name=user["last_name"],
                email=user["email"],
                subscription_type=user["subscription_type"],
                super_user=user["super_user"],
                disabled=user["disabled"],
                created=user["created"],
            )
            for user in users
        ]

        return ux

    @staticmethod
    def as_df(ux: List["User"]) -> pd.DataFrame:
        """Return the details of User instances as a pandas dataframe.

        Args:
            ux: List of user instances.

        Returns:
            Details of all the User in a dataframe.

        Raises:
            ConnectionError: If the server address is invalid or not reachable.

        An example to list the available users:

        ```python
        ux = Model.ls()
        Model.as_df(ux)
        ```
        """
        lists = get_attributes_from_instances(ux, User.USER_COLS)  # type: ignore
        return generate_df(lists, User.USER_COLS)

    @staticmethod
    def disable(user_id: int) -> pd.DataFrame:
        """Disable a user in the server.

        Args:
            user_id: User id to disabled.

        Returns:
            A pandas DataFrame encapsulating the details of the disabled user.

        Raises:
            ConnectionError: If the server address is invalid or not reachable.

        An example to disable a user:

        ```python
        User.disable(user_id=1)
        ```
        """

        response = Client._delete_data(relative_url=f"/user/{user_id}")

        return pd.DataFrame(response, index=[0])[User.USER_COLS]

    @staticmethod
    def enable(user_id: int) -> pd.DataFrame:
        """Enable a disabled user in the server.

        Args:
            user_id: User id to enable.

        Returns:
            A pandas DataFrame encapsulating the details of the enabled user.

        Raises:
            ConnectionError: If the server address is invalid or not reachable.

        An example to enable a disabled user:

        ```python
        User.enable(user_id=1)
        ```
        """

        response = Client._get_data(relative_url=f"/user/{user_id}/enable")

        return pd.DataFrame(response, index=[0])[User.USER_COLS]

    @staticmethod
    def update(
        user_id: int,
        username: Optional[str] = None,
        first_name: Optional[str] = None,
        last_name: Optional[str] = None,
        email: Optional[str] = None,
        password: Optional[str] = None,
    ) -> pd.DataFrame:
        """Update existing user details in the server.

        Args:
            user_id: User id in the server.
            username: New username for the user.
            first_name: New first name for the user.
            last_name: New last name for the user.
            email: New email for the user.
            password: New password for the user.

        Returns:
            A pandas DataFrame encapsulating the updated user details.

        Raises:
            ConnectionError: If the server address is invalid or not reachable.

        An example to update the username for an existing user:

        ```python
        User.update(user_id=1, username="new_username")
        ```
        """

        body = dict(
            username=username,
            first_name=first_name,
            last_name=last_name,
            email=email,
            password=password,
        )

        response = Client._post_data(relative_url=f"/user/{user_id}/update", data=body)

        return pd.DataFrame(response, index=[0])[User.USER_COLS]
