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

__all__ = ["APIKey"]

# Cell

from typing import *

# Internal Cell

import os

from datetime import datetime, timedelta, date

import pandas as pd
from fastcore.foundation import patch

from .client import Client
from .user import User
from ..logger import get_logger, set_level
from ..helper import (
    get_data,
    post_data,
    delete_data,
    generate_df,
    get_attributes_from_instances,
    check_and_append_otp_query_param,
)

# Internal Cell

logger = get_logger(__name__)

# Cell


class APIKey:
    """A class for managing the ApiKeys in the server.

    Both the ApiKey and the token can be used for accessing the airt services. However, there is a slight difference in generating and managing the two.

    For generating the ApiKey, you first need to get the developer token. Please refer to `Client.get_token` method documentation to generate one.

    After logging in with your developer token, you can create any number of new ApiKeys and can set an expiration date individually. You can also access
    other methods available in the APIKey class to list, revoke the ApiKey at any time.
    """

    API_KEY_COLS = ["uuid", "name", "created", "expiry", "disabled"]

    def __init__(
        self,
        uuid: str,
        name: Optional[str] = None,
        expiry: Optional[str] = None,
        disabled: Optional[bool] = None,
        created: Optional[str] = None,
    ):
        """Constructs a new User instance.

        Args:
            uuid: ApiKey uuid.
            name: ApiKey name.
            expiry: ApiKey expiry date.
            disabled: Flag to indicate the status of the ApiKey.
            created: ApiKey creation date.
        """
        self.uuid = uuid
        self.name = name
        self.expiry = expiry
        self.disabled = disabled
        self.created = created

    @staticmethod
    def create(
        name: str,
        expiry: Optional[Union[int, timedelta, datetime]] = None,
        otp: Optional[str] = None,
    ) -> Dict[str, str]:
        """Create a new ApiKey

        !!! note

            - The name of the ApiKey must be unique. If not, an exception will be raised while creating a new key with an existing key's name.

            - The expiry for an ApiKey is optional, if not passed then the default value **None** will be used to create an ApiKey with no expiry date!

        Args:
            name: The name of the ApiKey.
            expiry: The validity for the ApiKey. This can be an integer representing the number of days till expiry, can be
                an instance of timedelta (timedelta(days=x)) or can be an instance of datetime. If not passed, then the default value
                **None** will be used to create a ApiKey that will never expire!
            otp: Dynamically generated six-digit verification code from the authenticator app. Please pass this
                parameter only if the MFA is enabled for your account.

        Returns:
            The ApiKey and its type as a dictionary.

        Raises:
            ValueException: If the user is not authenticated.
            ValueException: If the user tries to create a new ApiKey with an existing key name.
            ValueException: If the OTP is invalid.
            ConnectionError: If the server address is invalid or not reachable.

        An example to create a new ApiKey with 1 year validity:

        ```python
        Client.get_token()

        APIKey.create(
            name="unique_key_name"
            expiry=365
        )
        ```
        """
        if expiry is None:
            expiry_date = expiry
        else:
            if isinstance(expiry, int):
                delta = datetime.now() + timedelta(days=expiry)
            elif isinstance(expiry, timedelta):
                delta = datetime.now() + expiry
            else:
                delta = expiry

            expiry_date = delta.strftime("%Y-%m-%dT%H:%M")

        return Client._post_data(
            relative_url="/apikey",
            data=dict(name=name, expiry=expiry_date, otp=otp),
        )

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

        Args:
            ax: List of ApiKey instances.

        Returns:
            Details of all the ApiKeys in a dataframe.

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

        An example to list the available ApiKeys:

        ```python
        ax = APIKey.ls()
        APIKey.as_df(ax)
        ```
        """
        lists = get_attributes_from_instances(ax, APIKey.API_KEY_COLS)  # type: ignore
        return generate_df(lists, APIKey.API_KEY_COLS)

    @staticmethod
    def ls(
        user: Optional[str] = None,
        offset: int = 0,
        limit: int = 100,
        include_disabled: bool = False,
        otp: Optional[str] = None,
    ) -> List["APIKey"]:
        """Return the list of ApiKeys instances.

        Args:
            user: user_uuid/username associated with the ApiKey. Please call `User.details` method to get your user_uuid.
                If not passed, then the currently logged-in user_id will be used.
            offset: The number of ApiKeys to offset at the beginning. If None, then the default value 0 will be used.
            limit: The maximum number of ApiKeys to return from the server. If None, then the default value 100 will be used.
            include_disabled: If set to **True**, then the disabled ApiKeys will also be included in the result.
            otp: Dynamically generated six-digit verification code from the authenticator app. Please pass this
                parameter only if the MFA is enabled for your account.

        Returns:
            A list of ApiKey instances.

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

        An example to list the available ApiKeys:

        ```python
        APIKey.ls()
        ```
        """
        user_uuid = User.details(user=user, otp=otp)["uuid"]

        url = f"/{user_uuid}/apikey?include_disabled={include_disabled}&offset={offset}&limit={limit}"
        apikeys = Client._get_data(
            relative_url=check_and_append_otp_query_param(url, otp)
        )

        ax = [
            APIKey(
                uuid=apikey["uuid"],
                name=apikey["name"],
                expiry=apikey["expiry"],
                disabled=apikey["disabled"],
                created=apikey["created"],
            )
            for apikey in apikeys
        ]

        return ax

    @staticmethod
    def details(apikey: str, otp: Optional[str] = None) -> pd.DataFrame:
        """Return details of an ApiKey.

        Args:
            apikey: ApiKey uuid/name.
            otp: Dynamically generated six-digit verification code from the authenticator app. Please pass this
                parameter only if the MFA is enabled for your account.

        Returns:
            A pandas Dataframe encapsulating the details of the ApiKey.

        Raises:
            ValueException: If the ApiKey uuid is invalid.
            ValueException: If the OTP is invalid.
            ConnectionError: If the server address is invalid or not reachable.

        An example to get details of an ApiKey:

        ```python
        APIKey.details(apikey=api_key_name)
        ```
        """
        url = f"/apikey/{apikey}"
        details = Client._get_data(
            relative_url=check_and_append_otp_query_param(url, otp)
        )

        return pd.DataFrame(details, index=[0])[APIKey.API_KEY_COLS]

    @staticmethod
    def revoke(
        keys: Union[str, List[str]],
        user: Optional[str] = None,
        otp: Optional[str] = None,
    ) -> pd.DataFrame:
        """Revoke one or more ApiKeys

        Args:
            keys: ApiKey uuid/name to revoke. To revoke multiple keys, please pass the uuids/names as a list.
            user: user_uuid/username associated with the ApiKey. Please call `User.details` method to get your user_uuid/username.
                If not passed, then the currently logged-in user will be used.
            otp: Dynamically generated six-digit verification code from the authenticator app. Please pass this
                parameter only if the MFA is enabled for your account.

        Returns:
             A pandas Dataframe encapsulating the details of the deleted ApiKey.

        Raises:
            ValueException: If the ApiKey uuid is invalid.
            ValueException: If the user_uuid is invalid.
            ValueException: If the OTP is invalid.
            ConnectionError: If the server address is invalid or not reachable.

        An example to delete an ApiKey:

        ```python
        APIKey.revoke(keys=api_key_name)
        ```
        """
        user_uuid = User.details(user=user, otp=otp)["uuid"]
        _keys = keys if isinstance(keys, list) else [keys]

        response_list = []

        for key_uuid in _keys:
            url = f"/{user_uuid}/apikey/{key_uuid}"
            response = Client._delete_data(
                relative_url=check_and_append_otp_query_param(url, otp)
            )
            response_list.append(response)

        return pd.DataFrame(response_list)[APIKey.API_KEY_COLS]
