######################################################################
#
# File: b2sdk/_internal/application_key.py
#
# Copyright 2021 Backblaze Inc. All Rights Reserved.
#
# License https://www.backblaze.com/using_b2_code.html
#
######################################################################
from __future__ import annotations


class BaseApplicationKey:
    """Common methods for ApplicationKey and FullApplicationKey."""

    def __init__(
        self,
        key_name: str,
        application_key_id: str,
        capabilities: list[str],
        account_id: str,
        expiration_timestamp_millis: int | None = None,
        bucket_ids: list[str] | None = None,
        name_prefix: str | None = None,
        options: list[str] | None = None,
    ):
        """
        :param key_name: name of the key, assigned by user
        :param application_key_id: key id, used to authenticate
        :param capabilities: list of capabilities assigned to this key
        :param account_id: account's id
        :param expiration_timestamp_millis: expiration time of the key
        :param bucket_id: if restricted to a bucket, this is the bucket's id
        :param name_prefix: if restricted to some files, this is their prefix
        :param options: reserved for future use
        """
        self.key_name = key_name
        self.id_ = application_key_id
        self.capabilities = capabilities
        self.account_id = account_id
        self.expiration_timestamp_millis = expiration_timestamp_millis
        self.bucket_ids = bucket_ids
        self.name_prefix = name_prefix
        self.options = options

    @classmethod
    def parse_response_dict(cls, response: dict):
        mandatory_args = {
            'key_name': response['keyName'],
            'application_key_id': response['applicationKeyId'],
            'capabilities': response['capabilities'],
            'account_id': response['accountId'],
        }

        optional_args = {
            'expiration_timestamp_millis': response.get('expirationTimestamp'),
            'bucket_ids': response.get('bucketIds'),
            'name_prefix': response.get('namePrefix'),
            'options': response.get('options'),
        }
        return {
            **mandatory_args,
            **{key: value for key, value in optional_args.items() if value is not None},
        }

    def has_capabilities(self, capabilities) -> bool:
        """checks whether the key has ALL of the given capabilities"""
        return len(set(capabilities) - set(self.capabilities)) == 0

    def as_dict(self):
        """Represent the key as a dict, like the one returned by B2 cloud"""
        mandatory_keys = {
            'keyName': self.key_name,
            'applicationKeyId': self.id_,
            'capabilities': self.capabilities,
            'accountId': self.account_id,
        }
        optional_keys = {
            'expirationTimestamp': self.expiration_timestamp_millis,
            'bucketIds': self.bucket_ids,
            'namePrefix': self.name_prefix,
            'options': self.options,
        }
        return {
            **mandatory_keys,
            **{key: value for key, value in optional_keys.items() if value is not None},
        }


class ApplicationKey(BaseApplicationKey):
    """Dataclass for storing info about an application key returned by delete-key or list-keys."""

    @classmethod
    def from_api_response(cls, response: dict) -> ApplicationKey:
        """Create an ApplicationKey object from a delete-key or list-key response (a parsed json object)."""
        return cls(**cls.parse_response_dict(response))


class FullApplicationKey(BaseApplicationKey):
    """Dataclass for storing info about an application key, including the actual key, as returned by create-key."""

    def __init__(
        self,
        key_name: str,
        application_key_id: str,
        application_key: str,
        capabilities: list[str],
        account_id: str,
        expiration_timestamp_millis: int | None = None,
        bucket_ids: list[str] | None = None,
        name_prefix: str | None = None,
        options: list[str] | None = None,
    ):
        """
        :param key_name: name of the key, assigned by user
        :param application_key_id: key id, used to authenticate
        :param application_key: the actual secret key
        :param capabilities: list of capabilities assigned to this key
        :param account_id: account's id
        :param expiration_timestamp_millis: expiration time of the key
        :param bucket_id: if restricted to a bucket, this is the bucket's id
        :param name_prefix: if restricted to some files, this is their prefix
        :param options: reserved for future use
        """
        self.application_key = application_key
        super().__init__(
            key_name=key_name,
            application_key_id=application_key_id,
            capabilities=capabilities,
            account_id=account_id,
            expiration_timestamp_millis=expiration_timestamp_millis,
            bucket_ids=bucket_ids,
            name_prefix=name_prefix,
            options=options,
        )

    @classmethod
    def from_create_response(cls, response: dict) -> FullApplicationKey:
        """Create a FullApplicationKey object from a create-key response (a parsed json object)."""
        return cls(**cls.parse_response_dict(response))

    @classmethod
    def parse_response_dict(cls, response: dict):
        result = super().parse_response_dict(response)
        result['application_key'] = response['applicationKey']
        return result

    def as_dict(self):
        """Represent the key as a dict, like the one returned by B2 cloud"""
        return {
            **super().as_dict(),
            'applicationKey': self.application_key,
        }
