import json

import boto3
from botocore.exceptions import ClientError

from edpconfigprovider import ConfigProvider
from edpconfigprovider.exceptions import NoConfigurationException


class AwsAppconfigProvider(ConfigProvider):
    _CLIENT = None

    def __init__(
        self,
        application_name: str,
        profile_name: str,
        environment_name: str,
    ):
        self.application_name = application_name
        self.profile_name = profile_name
        self.environment_name = environment_name
        self._configuration_token = None

    @classmethod
    def get_appconfig_data_client(cls):
        if cls._CLIENT is None:
            cls._CLIENT = boto3.client("appconfigdata")
        return cls._CLIENT

    def _ensure_session(self):
        if self._configuration_token is None:
            client = self.get_appconfig_data_client()
            session = client.start_configuration_session(
                ApplicationIdentifier=self.application_name,
                ConfigurationProfileIdentifier=self.profile_name,
                EnvironmentIdentifier=self.environment_name,
                RequiredMinimumPollIntervalInSeconds=15,
            )
            self._configuration_token = session["InitialConfigurationToken"]

    def get_latest_config_version(self):
        try:
            client = self.get_appconfig_data_client()
            self._ensure_session()
            response = client.get_latest_configuration(
                ConfigurationToken=self._configuration_token
            )
            self._configuration_token = response["NextPollConfigurationToken"]
            return json.loads(response["Configuration"].read())
        except ClientError:
            self._configuration_token = None
            raise NoConfigurationException(
                configuration_name=f"{self.application_name}/{self.environment_name}/{self.profile_name}"
            )

    def get_configuration(self) -> dict:
        return self.get_latest_config_version()
