<reponame>u93/multa-metrics-collector
from aws_cdk import core
from multacdkrecipies import (
    AwsApiGatewayLambdaFanOutBE,
    AwsApiGatewayLambdaPipes,
    AwsIotAnalyticsSimplePipeline,
    AwsLambdaFunctionsCluster,
    AwsLambdaLayerVenv,
    AwsS3BucketsCluster,
    AwsSsmString,
    AwsUserServerlessBackend,
)

from src.infrastructure.configs import (
    analytics_cold_path_config,
    base_configs,
    serverless_rest_api_configs,
    user_backend_config,
)


class BaseStack(core.Stack):
    """
    Base Stack for MultaMetrics Backend. Will contain common configurations and resources for other Stacks
    """

    def __init__(self, scope: core.Construct, id: str, config=None, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        self._base_stack_lambdalayer = AwsLambdaLayerVenv(
            self,
            id=f"BaseStack-LambdaLayer-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["BASE_CONFIG_LAMBDA_LAYER"],
        )
        layer_arn = self._base_stack_lambdalayer.lambda_layer.layer_version_arn

        self._base_stack_backend_ssm = AwsSsmString(
            self,
            id=f"BaseStack-Ssm-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["BASE_CONFIG_SSM"],
        )

        for lambda_function in config["config"]["BASE_CONFIG_FUNCTIONS"]["functions"]:
            lambda_function["layers"].append(layer_arn)
        self._helper_functions = AwsLambdaFunctionsCluster(
            self,
            id=f"BaseBackend-Functions-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["BASE_CONFIG_FUNCTIONS"],
        )

        self._base_backend_buckets = AwsS3BucketsCluster(
            self,
            id=f"BaseBackend-Buckets-{config['environ']}",
            prefix="multa-backend",
            environment=config["environ"],
            configuration=config["config"]["BASE_CONFIG_BUCKETS"],
        )


class UserBackendStack(core.Stack):
    """
    User Backend Stack for MultaMetrics Backend. Will contain resources necessary to handle users and auth.
    """

    def __init__(self, scope: core.Construct, id: str, config=None, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        self._user_serverless_backend_lambdalayer = AwsLambdaLayerVenv(
            self,
            id=f"UserServerlessBE-LambdaLayer-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["USER_BACKEND_LAMBDA_LAYER"],
        )
        layer_arn = self._user_serverless_backend_lambdalayer.lambda_layer.layer_version_arn

        self._user_serverless_backend_ssm = AwsSsmString(
            self,
            id=f"UserServerlessBE-Ssm-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["USER_BACKEND_SSM"],
        )

        config["config"]["USER_BACKEND"]["authorizer_function"]["origin"]["layers"].append(layer_arn)
        config["config"]["USER_BACKEND"]["user_pool"]["triggers"]["post_confirmation"]["layers"].append(layer_arn)
        self._user_serverless_backend = AwsUserServerlessBackend(
            self,
            id=f"UserServerlessBE-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["USER_BACKEND"],
        )

    def lambda_authorizer_arn(self):
        return self._user_serverless_backend.authorizer_function.function_arn


class UserApisBackend(core.Stack):
    """
    API Constructs to be used by MultaMetrics frontend to handle user settings, plans, roles, organizations.
    """

    def __init__(self, scope: core.Construct, id: str, config=None, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        self._fan_out_api_lambdalayer = AwsLambdaLayerVenv(
            self,
            id=f"AnalyticsColdPath-LambdaLayer-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["SERVERLESS_REST_API_LAMBDA_LAYER"],
        )
        layer_arn = self._fan_out_api_lambdalayer.lambda_layer.layer_version_arn

        for function in config["config"]["SERVERLESS_REST_API"]["api"]["resource_trees"]:
            function["handler"]["layers"].append(layer_arn)

        self._serverless_rest_api = AwsApiGatewayLambdaPipes(
            self,
            id=f"ServerlessRestApi-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["SERVERLESS_REST_API"],
        )


class AnalyticsHotPathStack(core.Stack):
    """
    Hot Analytics Stack for MultaMetrics Backend. Will contain resources necessary for a rapid ingestion and
    representation of data.
    """

    def __init__(self, scope: core.Construct, id: str, config=None, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)


class AnalyticsColdPathStack(core.Stack):
    """
    Cold Analytics Stack for MultaMetrics Backend. Will contain resources necessary for a storage, ingestion and
    analysis and representation of timeseries data.
    """

    def __init__(self, scope: core.Construct, id: str, config=None, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        self._fan_out_api_lambdalayer = AwsLambdaLayerVenv(
            self,
            id=f"AnalyticsColdPath-LambdaLayer-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["ANALYTICS_FAN_OUT_LAMBDA_LAYER"],
        )
        layer_arn = self._fan_out_api_lambdalayer.lambda_layer.layer_version_arn

        for function in config["config"]["ANALYTICS_FAN_OUT_API"]["functions"]:
            function["layers"].append(layer_arn)
        config["config"]["ANALYTICS_FAN_OUT_API"]["api"]["authorizer_function"]["origin"]["layers"].append(layer_arn)

        fan_out_api = AwsApiGatewayLambdaFanOutBE(
            self,
            id=f"AnalyticsColdPath-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["ANALYTICS_FAN_OUT_API"],
        )


app = core.App()

for environment, configuration in base_configs.BASE_CONFIGS.items():
    # print(configuration)
    config = dict(environ=environment, config=configuration)
    base_backend = BaseStack(app, id=f"BackendBaseStack-{environment}", config=config)

lambda_authorizers = dict()
for environment, configuration in user_backend_config.USER_BACKEND_CONFIGS.items():
    # print(configuration)
    config = dict(environ=environment, config=configuration)
    user_backend = UserBackendStack(app, id=f"UserOrganizationStack-{environment}", config=config)

    lambda_authorizers[environment] = user_backend.lambda_authorizer_arn()

for environment, configuration in serverless_rest_api_configs.SERVERLESS_REST_API_CONFIGS.items():
    configuration["SERVERLESS_REST_API"]["api"]["authorizer_function"]["imported"]["arn"] = lambda_authorizers[
        environment
    ]
    config = dict(environ=environment, config=configuration)
    UserApisBackend(app, id=f"UserApisBackend-{environment}", config=config)

for environment, configuration in analytics_cold_path_config.ANALYTICS_COLD_PATH_CONFIGS.items():
    config = dict(environ=environment, config=configuration)
    AnalyticsColdPathStack(app, id=f"AnalyticsColdPathStack-{environment}", config=config)


app.synth()

from aws_cdk import core
from multacdkrecipies import (
    AwsApiGatewayLambdaFanOutBE,
    AwsApiGatewayLambdaPipes,
    AwsIotAnalyticsSimplePipeline,
    AwsLambdaFunctionsCluster,
    AwsLambdaLayerVenv,
    AwsS3BucketsCluster,
    AwsSsmString,
    AwsUserServerlessBackend,
)

from src.infrastructure.configs import (
    analytics_cold_path_config,
    base_configs,
    serverless_rest_api_configs,
    user_backend_config,
)


class BaseStack(core.Stack):
    """
    Base Stack for MultaMetrics Backend. Will contain common configurations and resources for other Stacks
    """

    def __init__(self, scope: core.Construct, id: str, config=None, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        self._base_stack_lambdalayer = AwsLambdaLayerVenv(
            self,
            id=f"BaseStack-LambdaLayer-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["BASE_CONFIG_LAMBDA_LAYER"],
        )
        layer_arn = self._base_stack_lambdalayer.lambda_layer.layer_version_arn

        self._base_stack_backend_ssm = AwsSsmString(
            self,
            id=f"BaseStack-Ssm-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["BASE_CONFIG_SSM"],
        )

        for lambda_function in config["config"]["BASE_CONFIG_FUNCTIONS"]["functions"]:
            lambda_function["layers"].append(layer_arn)
        self._helper_functions = AwsLambdaFunctionsCluster(
            self,
            id=f"BaseBackend-Functions-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["BASE_CONFIG_FUNCTIONS"],
        )

        self._base_backend_buckets = AwsS3BucketsCluster(
            self,
            id=f"BaseBackend-Buckets-{config['environ']}",
            prefix="multa-backend",
            environment=config["environ"],
            configuration=config["config"]["BASE_CONFIG_BUCKETS"],
        )


class UserBackendStack(core.Stack):
    """
    User Backend Stack for MultaMetrics Backend. Will contain resources necessary to handle users and auth.
    """

    def __init__(self, scope: core.Construct, id: str, config=None, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        self._user_serverless_backend_lambdalayer = AwsLambdaLayerVenv(
            self,
            id=f"UserServerlessBE-LambdaLayer-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["USER_BACKEND_LAMBDA_LAYER"],
        )
        layer_arn = self._user_serverless_backend_lambdalayer.lambda_layer.layer_version_arn

        self._user_serverless_backend_ssm = AwsSsmString(
            self,
            id=f"UserServerlessBE-Ssm-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["USER_BACKEND_SSM"],
        )

        config["config"]["USER_BACKEND"]["authorizer_function"]["origin"]["layers"].append(layer_arn)
        config["config"]["USER_BACKEND"]["user_pool"]["triggers"]["post_confirmation"]["layers"].append(layer_arn)
        self._user_serverless_backend = AwsUserServerlessBackend(
            self,
            id=f"UserServerlessBE-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["USER_BACKEND"],
        )

    def lambda_authorizer_arn(self):
        return self._user_serverless_backend.authorizer_function.function_arn


class UserApisBackend(core.Stack):
    """
    API Constructs to be used by MultaMetrics frontend to handle user settings, plans, roles, organizations.
    """

    def __init__(self, scope: core.Construct, id: str, config=None, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        self._fan_out_api_lambdalayer = AwsLambdaLayerVenv(
            self,
            id=f"AnalyticsColdPath-LambdaLayer-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["SERVERLESS_REST_API_LAMBDA_LAYER"],
        )
        layer_arn = self._fan_out_api_lambdalayer.lambda_layer.layer_version_arn

        for function in config["config"]["SERVERLESS_REST_API"]["api"]["resource_trees"]:
            function["handler"]["layers"].append(layer_arn)

        self._serverless_rest_api = AwsApiGatewayLambdaPipes(
            self,
            id=f"ServerlessRestApi-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["SERVERLESS_REST_API"],
        )


class AnalyticsHotPathStack(core.Stack):
    """
    Hot Analytics Stack for MultaMetrics Backend. Will contain resources necessary for a rapid ingestion and
    representation of data.
    """

    def __init__(self, scope: core.Construct, id: str, config=None, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)


class AnalyticsColdPathStack(core.Stack):
    """
    Cold Analytics Stack for MultaMetrics Backend. Will contain resources necessary for a storage, ingestion and
    analysis and representation of timeseries data.
    """

    def __init__(self, scope: core.Construct, id: str, config=None, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        self._fan_out_api_lambdalayer = AwsLambdaLayerVenv(
            self,
            id=f"AnalyticsColdPath-LambdaLayer-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["ANALYTICS_FAN_OUT_LAMBDA_LAYER"],
        )
        layer_arn = self._fan_out_api_lambdalayer.lambda_layer.layer_version_arn

        for function in config["config"]["ANALYTICS_FAN_OUT_API"]["functions"]:
            function["layers"].append(layer_arn)
        config["config"]["ANALYTICS_FAN_OUT_API"]["api"]["authorizer_function"]["origin"]["layers"].append(layer_arn)

        fan_out_api = AwsApiGatewayLambdaFanOutBE(
            self,
            id=f"AnalyticsColdPath-{config['environ']}",
            prefix="multa_backend",
            environment=config["environ"],
            configuration=config["config"]["ANALYTICS_FAN_OUT_API"],
        )


app = core.App()

for environment, configuration in base_configs.BASE_CONFIGS.items():
    # print(configuration)
    config = dict(environ=environment, config=configuration)
    base_backend = BaseStack(app, id=f"BackendBaseStack-{environment}", config=config)

lambda_authorizers = dict()
for environment, configuration in user_backend_config.USER_BACKEND_CONFIGS.items():
    # print(configuration)
    config = dict(environ=environment, config=configuration)
    user_backend = UserBackendStack(app, id=f"UserOrganizationStack-{environment}", config=config)

    lambda_authorizers[environment] = user_backend.lambda_authorizer_arn()

for environment, configuration in serverless_rest_api_configs.SERVERLESS_REST_API_CONFIGS.items():
    configuration["SERVERLESS_REST_API"]["api"]["authorizer_function"]["imported"]["arn"] = lambda_authorizers[
        environment
    ]
    config = dict(environ=environment, config=configuration)
    UserApisBackend(app, id=f"UserApisBackend-{environment}", config=config)

for environment, configuration in analytics_cold_path_config.ANALYTICS_COLD_PATH_CONFIGS.items():
    config = dict(environ=environment, config=configuration)
    AnalyticsColdPathStack(app, id=f"AnalyticsColdPathStack-{environment}", config=config)


app.synth()
Base Stack for MultaMetrics Backend. Will contain common configurations and resources for other Stacks User Backend Stack for MultaMetrics Backend. Will contain resources necessary to handle users and auth. API Constructs to be used by MultaMetrics frontend to handle user settings, plans, roles, organizations. Hot Analytics Stack for MultaMetrics Backend. Will contain resources necessary for a rapid ingestion and     representation of data. Cold Analytics Stack for MultaMetrics Backend. Will contain resources necessary for a storage, ingestion and     analysis and representation of timeseries data. # print(configuration) # print(configuration)