import os
from typing import Dict, Optional, TypeVar

from ... import ConfigProvider

T = TypeVar("T")

# JSON Local File
JSON = "json"

# AWS Providers
AWS_APPCONFIG = "aws_appconfig"
AWS_APPCONFIG_AGENT = "aws_appconfig_agent"
AWS_SSM = "aws_ssm"


class ProviderParameters:
    def __init__(
        self,
        config_prefix: str = None,
        replace_parameters: Dict[str, str] = None,
        **kwargs
    ):
        self.kwargs = kwargs
        self.replace_parameters = replace_parameters
        self._config_prefix = config_prefix

    @staticmethod
    def _get_parameter_env(*args: str) -> str:
        return "_".join([arg.upper() for arg in args if arg is not None])

    def get_parameter(
        self,
        parameter_name: str,
        provider_prefix: Optional[str] = None,
        default_value: Optional[str] = None,
        fallback_without_prefix: bool = False
    ) -> Optional[str]:
        if provider_prefix in self.kwargs and parameter_name in self.kwargs[provider_prefix]:
            return self.kwargs[provider_prefix][parameter_name]

        value = os.environ.get(
            self._get_parameter_env(self._config_prefix, provider_prefix, parameter_name)
        )

        if value is None and fallback_without_prefix and self._config_prefix is not None:
            value = os.environ.get(
                self._get_parameter_env(None, provider_prefix, parameter_name)
            )

        if value is None:
            value = default_value

        if self.replace_parameters and value is not None:
            value = value.format(**self.replace_parameters)
        return value

    def get_bool_parameter(
        self,
        parameter_name: str,
        provider_prefix: Optional[str] = None,
        default_value: bool = False
    ) -> bool:
        ret = self.get_parameter(provider_prefix=provider_prefix, parameter_name=parameter_name)

        if ret is not None:
            return ret.strip().lower() in ("true", "yes", "1")

        return default_value


def get_provider(provider_type: str, parameters: ProviderParameters) -> ConfigProvider:
    if provider_type == JSON:
        from ...impl.json import JsonConfigProvider
        return JsonConfigProvider(json_path=parameters.get_parameter("config_path"))
    elif provider_type == AWS_APPCONFIG:
        from ...impl.aws.appconfig import AwsAppConfigProvider
        return AwsAppConfigProvider(
            application_name=parameters.get_parameter(
                parameter_name="application_name",
                provider_prefix=AWS_APPCONFIG,
            ),
            profile_name=parameters.get_parameter(
                parameter_name="profile_name",
                provider_prefix=AWS_APPCONFIG,
            ),
            environment_name=parameters.get_parameter(
                parameter_name="environment_name",
                provider_prefix=AWS_APPCONFIG,
            ),
        )
    elif provider_type == AWS_APPCONFIG_AGENT:
        from ...impl.aws.appconfig import AwsAppconfigAgentProvider
        return AwsAppconfigAgentProvider(
            application_name=parameters.get_parameter(
                parameter_name="application_name",
                provider_prefix=AWS_APPCONFIG,
            ),
            profile_name=parameters.get_parameter(
                parameter_name="profile_name",
                provider_prefix=AWS_APPCONFIG,
            ),
            environment_name=parameters.get_parameter(
                parameter_name="environment_name",
                provider_prefix=AWS_APPCONFIG,
            ),
        )
    elif provider_type == AWS_SSM:
        from ...impl.aws.ssm import AwsSsmProvider

        return AwsSsmProvider(
            parameter_path=parameters.get_parameter(
                parameter_name="parameter_path",
                provider_prefix=AWS_SSM
            ),
            recursive=parameters.get_bool_parameter(
                parameter_name="recursive",
                provider_prefix=AWS_SSM,
                default_value=True
            ),
            split_path=parameters.get_bool_parameter(
                parameter_name="split_path",
                provider_prefix=AWS_SSM,
                default_value=True
            ),
            decrypt=parameters.get_bool_parameter(
                parameter_name="decrypt",
                provider_prefix=AWS_SSM,
                default_value=True
            ),
        )

    raise ValueError(f"Unknown provider type: {provider_type}")
