# Copyright 2021 Chris Rose

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Handling of sensitive data stored in AWS SecretsManager
"""
import logging

import attr
import boto3

from environ._environ_config import CNF_KEY, RAISE, _ConfigEntry

from ._utils import _get_default_secret


log = logging.getLogger(__name__)


def convert_secret(key):
    def converter(value):
        if isinstance(value, str):
            return value
        return value[key]

    return converter


def _build_secretsmanager_client():
    client = boto3.client("secretsmanager")
    log.debug("Created a secretsmanager client %s", client)
    return client


@attr.s(init=False)
class SecretsManagerSecrets:
    """
    Load secrets from the AWS secretsmanager.

    The secret name should be stored in the environment variable

    .. versionadded:: 21.4.0
    """

    def __init__(self, client=None):
        self._client = client

    @property
    def client(self):
        if self._client is None:
            self._client = _build_secretsmanager_client()
        return self._client

    def secret(
        self,
        default=RAISE,
        converter=convert_secret("SecretString"),
        name=None,
        help=None,
    ):
        """
        Declare a secrets manager secret on an `environ.config`-decorated class

        All parameters work just like in `environ.var`.
        """
        return attr.ib(
            default=default,
            metadata={
                CNF_KEY: _ConfigEntry(name, default, None, self._get, help)
            },
            converter=converter,
        )

    def _get(self, environ, metadata, prefix, name):
        ce = metadata[CNF_KEY]
        if ce.name:
            secret_name_envvar = ce.name
            log.debug(
                "override env variable with explicit name %s",
                secret_name_envvar,
            )
        else:
            parts = prefix + (name,)
            secret_name_envvar = "_".join(parts).upper()
            log.debug(
                "secret name environment variable %s", secret_name_envvar
            )

        try:
            secret_name = environ[secret_name_envvar]
        except KeyError:
            # missing the environment; let's try to get the default
            log.debug(
                "no key %s in environment, using default=%s",
                secret_name_envvar,
                ce.default,
            )
            return _get_default_secret(secret_name_envvar, ce.default)
        log.debug("secret name: %s", secret_name)

        return self.client.get_secret_value(SecretId=secret_name)
