#  Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
#  SPDX-License-Identifier: Apache-2.0


from typing import Any, Dict, Optional, Union

import aws_cdk as cdk
import constructs
from aws_cdk import Duration
from aws_cdk import aws_dynamodb as dynamodb
from aws_cdk import aws_ec2 as ec2
from aws_cdk import aws_ecs as ecs
from aws_cdk import aws_events as events
from aws_cdk import aws_events_targets as events_targets
from aws_cdk import aws_iam as iam
from aws_cdk import aws_lambda as _lambda
from aws_cdk import aws_logs as logs
from aws_cdk.aws_events import Schedule
from res.constants import (  # type: ignore
    AD_SYNC_LOCK_TABLE,
    AD_SYNC_STATUS_SUBMISSION_TIME_KEY,
    AD_SYNC_STATUS_TABLE,
    AD_SYNC_STATUS_TASK_ID_KEY,
    AD_SYNC_STATUS_TTL_KEY,
    ENVIRONMENT_NAME_KEY,
    LOCK_DB_HASH_KEY,
    LOCK_DB_RANGE_KEY,
    MODULE_NAME_DIRECTORY_SERVICE,
)
from res.resources import cluster_settings  # type: ignore

from idea.batteries_included.parameters.parameters import BIParameters
from idea.infrastructure.install.constants import (
    RES_COMMON_LAMBDA_RUNTIME,
    RES_ECR_REPO_NAME_SUFFIX,
)
from idea.infrastructure.install.constructs.base import ResBaseConstruct
from idea.infrastructure.install.ddb_tables.base import RESDDBTableBase
from idea.infrastructure.install.ddb_tables.list import RESDDBTable
from idea.infrastructure.install.handlers import scheduled_ad_sync_handler
from idea.infrastructure.install.parameters.common import CommonKey
from idea.infrastructure.install.parameters.parameters import RESParameters
from idea.infrastructure.install.utils import InfraUtils
from idea.infrastructure.resources.lambda_functions.custom_resource.ad_sync_resources_populator_lambda import (
    ad_sync_resources_populator_handler,
)
from idea.infrastructure.resources.lambda_functions.custom_resource.ad_sync_task_terminator_lambda import (
    handler,
)


class ADSyncStack(ResBaseConstruct):
    """
    Setup infrastructure for the AD Sync process
    """

    def __init__(
        self,
        scope: constructs.Construct,
        lambda_layer: _lambda.LayerVersion,
        parameters: Union[RESParameters, BIParameters] = RESParameters(),
        registry_name: Optional[str] = None,
    ):
        self.parameters = parameters
        self.cluster_name = parameters.get_str(CommonKey.CLUSTER_NAME)
        self.registry_name = registry_name if registry_name else ""
        self.lambda_layer = lambda_layer

        super().__init__(
            self.cluster_name,
            cdk.Aws.REGION,
            "ad-sync",
            scope,
            parameters,
        )

        self.nested_stack = cdk.NestedStack(
            scope,
            "ad-sync",
            description="Nested Stack for supporting AD Sync",
        )

        vpc = ec2.Vpc.from_vpc_attributes(
            self.nested_stack,
            "ExistingVpc",
            availability_zones=[""],
            vpc_id=self.parameters.get_str(CommonKey.VPC_ID),
            private_subnet_ids=[
                cdk.Fn.select(
                    0,
                    self.parameters.get(
                        CommonKey.INFRASTRUCTURE_HOST_SUBNETS
                    ).value_as_list,
                ),
                cdk.Fn.select(
                    1,
                    self.parameters.get(
                        CommonKey.INFRASTRUCTURE_HOST_SUBNETS
                    ).value_as_list,
                ),
            ],
        )
        self.ecs_cluster = ecs.Cluster(
            self.nested_stack,
            "ADSyncCluster",
            vpc=vpc,
            cluster_name=f"{self.cluster_name}-ad-sync-cluster",
        )

        self.build_ad_sync_security_group(vpc)
        self.build_ad_sync_lock_table()
        self.build_ad_sync_status_table()
        self.build_scheduled_event_ad_sync_infra()
        self.build_ad_sync_task_definition()
        self.terminate_ad_sync_ecs_task()
        self.build_ad_sync_resources_populator()

        self.nested_stack.node.add_dependency(self.lambda_layer)
        self.apply_permission_boundary(self.nested_stack)

    def build_ad_sync_security_group(self, vpc: ec2.IVpc) -> None:
        """
        Create the AD Sync Security Group.
        """
        self.ad_sync_security_group = ec2.SecurityGroup(
            self.nested_stack,
            "ADSyncSecurityGroup",
            security_group_name=f"{self.cluster_name}-ad-sync-security-group",
            vpc=vpc,
            description="Security group for AD Sync task",
        )

        self.ad_sync_security_group.add_egress_rule(
            ec2.Peer.ipv4("0.0.0.0/0"),
            ec2.Port.all_traffic(),
            description="Allow all outbound traffic by default",
        )
        self.add_common_tags(self.ad_sync_security_group)

    def build_ad_sync_lock_table(self) -> None:
        """
        Create the DynamoDB table used to lock AD Sync operations.
        """
        ad_sync_lock_table: RESDDBTable = RESDDBTable(
            id=AD_SYNC_LOCK_TABLE,
            module_id=MODULE_NAME_DIRECTORY_SERVICE,
            table_props=dynamodb.TableProps(
                partition_key=dynamodb.Attribute(
                    name=LOCK_DB_HASH_KEY, type=dynamodb.AttributeType.STRING
                ),
                sort_key=dynamodb.Attribute(
                    name=LOCK_DB_RANGE_KEY, type=dynamodb.AttributeType.STRING
                ),
            ),
        )
        self.ad_sync_lock_table = RESDDBTableBase(
            self.nested_stack,
            ad_sync_lock_table.id,
            self.cluster_name,
            ad_sync_lock_table,
        ).ddb_table

    def build_ad_sync_status_table(self) -> None:
        """
        Create the DynamoDB table for tracking AD Sync ECS task status.
        """
        ad_sync_status_table: RESDDBTable = RESDDBTable(
            id=AD_SYNC_STATUS_TABLE,
            module_id=MODULE_NAME_DIRECTORY_SERVICE,
            table_props=dynamodb.TableProps(
                partition_key=dynamodb.Attribute(
                    name=AD_SYNC_STATUS_TASK_ID_KEY, type=dynamodb.AttributeType.STRING
                ),
                sort_key=dynamodb.Attribute(
                    name=AD_SYNC_STATUS_SUBMISSION_TIME_KEY,
                    type=dynamodb.AttributeType.NUMBER,
                ),
                time_to_live_attribute=AD_SYNC_STATUS_TTL_KEY,
            ),
        )

        self.ad_sync_status_table = RESDDBTableBase(
            self.nested_stack,
            ad_sync_status_table.id,
            self.cluster_name,
            ad_sync_status_table,
        ).ddb_table

    def build_scheduled_event_ad_sync_infra(self) -> None:
        lambda_name = f"{self.cluster_name}-scheduled-ad-sync"
        scheduled_ad_sync_lambda_role = iam.Role(
            self.nested_stack,
            id="scheduled-ad-sync-role",
            role_name=f"{lambda_name}-role",
            assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
            description=f"{lambda_name}-role",
        )

        scheduled_ad_sync_lambda_role.attach_inline_policy(
            iam.Policy(
                self.nested_stack,
                id="scheduled-ad-sync-policy",
                policy_name=f"{lambda_name}-policy",
                statements=[
                    iam.PolicyStatement(
                        actions=["logs:CreateLogGroup"],
                        sid="CloudWatchLogsPermissions",
                        resources=["*"],
                    ),
                    iam.PolicyStatement(
                        actions=[
                            "logs:CreateLogStream",
                            "logs:PutLogEvents",
                            "logs:DeleteLogStream",
                        ],
                        sid="CloudWatchLogStreamPermissions",
                        resources=["*"],
                    ),
                    iam.PolicyStatement(
                        actions=[
                            "dynamodb:GetItem",
                            "dynamodb:Scan",
                        ],
                        sid="ClusterSettingsTablePermissions",
                        resources=[
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.cluster-settings",
                        ],
                    ),
                    iam.PolicyStatement(
                        actions=[
                            "dynamodb:GetItem",
                            "dynamodb:PutItem",
                            "dynamodb:DeleteItem",
                        ],
                        sid="ADSyncLockTablePermissions",
                        resources=[
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.ad-sync.distributed-lock",
                        ],
                    ),
                    iam.PolicyStatement(
                        actions=[
                            "dynamodb:Query",
                            "dynamodb:Scan",
                            "dynamodb:UpdateItem",
                            "dynamodb:PutItem",
                        ],
                        sid="ADSyncStatusTablePermissions",
                        resources=[
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.ad-sync.status",
                        ],
                    ),
                    iam.PolicyStatement(
                        actions=[
                            "ecs:RunTask",
                            "ecs:StopTask",
                            "ecs:ListTasks",
                        ],
                        resources=["*"],
                        conditions={
                            "ArnEquals": {"ecs:cluster": self.ecs_cluster.cluster_arn}
                        },
                    ),
                    iam.PolicyStatement(
                        actions=["iam:PassRole"],
                        resources=[
                            f"arn:{cdk.Aws.PARTITION}:iam::{cdk.Aws.ACCOUNT_ID}:role/{self.cluster_name}-ad-sync-task-role",
                        ],
                    ),
                    iam.PolicyStatement(
                        actions=["ec2:DescribeSecurityGroups"],
                        resources=["*"],
                    ),
                ],
            )
        )
        self.add_common_tags(scheduled_ad_sync_lambda_role)

        scheduled_ad_sync_lambda = _lambda.Function(
            self.nested_stack,
            id="scheduled-ad-sync",
            function_name=lambda_name,
            description=f"Lambda to send scheduled event to trigger ad sync",
            environment={
                "environment_name": self.cluster_name,
            },
            timeout=Duration.seconds(180),
            role=scheduled_ad_sync_lambda_role,
            runtime=RES_COMMON_LAMBDA_RUNTIME,
            **InfraUtils.get_handler_and_code_for_function(
                scheduled_ad_sync_handler.handler
            ),
            layers=[self.lambda_layer],
        )
        self.add_common_tags(scheduled_ad_sync_lambda)

        # CloudFormation that doesn't support Tags for Event Bridge rule currently:
        # Check https://github.com/aws/aws-cdk/issues/4907
        schedule_trigger_rule = events.Rule(
            self.nested_stack,
            id="ad-sync-schedule-rule",
            enabled=True,
            rule_name=f"{self.cluster_name}-ad-sync-schedule-rule",
            description="Event Rule to Trigger schedule AD sync EVERY hour",
            schedule=Schedule.cron(minute="0", hour="0/1"),  # every 1 hour
        )

        schedule_trigger_rule.add_target(
            events_targets.LambdaFunction(
                scheduled_ad_sync_lambda,
            )
        )

    def build_ad_sync_task_definition(self) -> None:
        ad_sync_task_role = self.build_ad_sync_task_role()
        self.task_definition = ecs.TaskDefinition(
            self.nested_stack,
            id="ad-sync-task-definition",
            compatibility=ecs.Compatibility.FARGATE,
            task_role=ad_sync_task_role,
            execution_role=ad_sync_task_role,
            memory_mib="1024",
            cpu="512",
            family=f"{self.cluster_name}-ad-sync-task-definition",
        )

        commands = " && ".join(
            [
                "source venv/bin/activate",
                "exec res-ad-sync",
            ]
        )
        self.task_definition.add_container(
            "ad-sync-task-container",
            image=ecs.ContainerImage.from_registry(self.registry_name),
            command=["/bin/sh", "-exc", commands],
            environment={
                "environment_name": self.cluster_name,
                "AWS_DEFAULT_REGION": cdk.Aws.REGION,
            },
            logging=ecs.LogDriver.aws_logs(
                stream_prefix="ecs",
                log_group=logs.LogGroup(
                    self.nested_stack,
                    "ad-sync-task-log-group",
                    log_group_name=f"{self.cluster_name}/ad-sync",
                    removal_policy=cdk.RemovalPolicy.DESTROY,
                ),
            ),
        )
        self.add_common_tags(self.task_definition)

    def build_ad_sync_task_role(self) -> iam.Role:
        ad_sync_task_role = iam.Role(
            self.nested_stack,
            id="ad-sync-task-role",
            role_name=f"{self.cluster_name}-ad-sync-task-role",
            assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
            description=f"ad-sync-task-role",
        )
        ad_sync_task_role.attach_inline_policy(
            iam.Policy(
                self.nested_stack,
                id="ad-sync-task-policy",
                policy_name=f"{self.cluster_name}-ad-sync-task-policy",
                statements=[
                    iam.PolicyStatement(
                        actions=["logs:CreateLogGroup"],
                        sid="CloudWatchLogsPermissions",
                        resources=["*"],
                    ),
                    iam.PolicyStatement(
                        actions=[
                            "logs:CreateLogStream",
                            "logs:PutLogEvents",
                            "logs:DeleteLogStream",
                        ],
                        sid="CloudWatchLogStreamPermissions",
                        resources=["*"],
                    ),
                    iam.PolicyStatement(
                        actions=["secretsmanager:GetSecretValue"],
                        sid="SecretsManagerPermissions",
                        resources=["*"],
                    ),
                    iam.PolicyStatement(
                        actions=[
                            "dynamodb:GetItem",
                            "dynamodb:Query",
                            "dynamodb:Scan",
                            "dynamodb:UpdateItem",
                            "dynamodb:PutItem",
                            "dynamodb:DeleteItem",
                        ],
                        sid="DynamoDBPermissions",
                        resources=[
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.cluster-settings",
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.accounts.users",
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.accounts.users/index/*",
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.accounts.groups",
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.accounts.group-members",
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.projects",
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.projects/index/*",
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.authz.role-assignments",
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.authz.role-assignments/index/*",
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.{AD_SYNC_STATUS_TABLE}",
                            f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.{AD_SYNC_STATUS_TABLE}/index/*",
                        ],
                    ),
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        resources=[
                            f"arn:{cdk.Aws.PARTITION}:ecr:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:repository/{self.cluster_name}{RES_ECR_REPO_NAME_SUFFIX}"
                        ],
                        actions=[
                            "ecr:BatchGetImage",
                            "ecr:DescribeRepositories",
                            "ecr:GetDownloadUrlForLayer",
                            "ecr:GetLifecyclePolicy",
                            "ecr:GetRepositoryPolicy",
                            "ecr:ListTagsForResource",
                        ],
                        sid="ECRPermissions",
                    ),
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        resources=["*"],
                        actions=[
                            "ecr:GetAuthorizationToken",
                        ],
                        sid="ECRAuthorizationPermissions",
                    ),
                ],
            )
        )
        self.add_common_tags(ad_sync_task_role)

        return ad_sync_task_role

    # Create a custom lambda to terminate AD sync ECS task before deleting AD sync ECS cluster
    def terminate_ad_sync_ecs_task(self) -> None:
        lambda_name = f"{self.cluster_name}-terminate-ad-sync-ecs-task"
        terminate_ad_sync_ecs_task_role = iam.Role(
            self.nested_stack,
            id="terminate-ad-sync-ecs-task-role",
            role_name=f"{lambda_name}-role",
            assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
            description=f"{lambda_name}-role",
        )

        terminate_ad_sync_ecs_task_policy = iam.Policy(
            self.nested_stack,
            id="terminate-ad-sync-ecs-task-policy",
            policy_name=f"{lambda_name}-policy",
            statements=[
                iam.PolicyStatement(
                    actions=["logs:CreateLogGroup"],
                    sid="CloudWatchLogsPermissions",
                    resources=["*"],
                ),
                iam.PolicyStatement(
                    actions=[
                        "logs:CreateLogStream",
                        "logs:PutLogEvents",
                        "logs:DeleteLogStream",
                    ],
                    sid="CloudWatchLogStreamPermissions",
                    resources=["*"],
                ),
                iam.PolicyStatement(
                    actions=[
                        "dynamodb:GetItem",
                        "dynamodb:PutItem",
                        "dynamodb:DeleteItem",
                    ],
                    sid="ADSyncLockTablePermissions",
                    resources=[
                        f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.ad-sync.distributed-lock",
                    ],
                ),
                iam.PolicyStatement(
                    actions=[
                        "dynamodb:Query",
                        "dynamodb:Scan",
                        "dynamodb:UpdateItem",
                        "dynamodb:PutItem",
                    ],
                    sid="ADSyncStatusTablePermissions",
                    resources=[
                        f"arn:{cdk.Aws.PARTITION}:dynamodb:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:table/{self.cluster_name}.ad-sync.status",
                    ],
                ),
                iam.PolicyStatement(
                    actions=[
                        "ecs:StopTask",
                        "ecs:ListTasks",
                        "ecs:DescribeTasks",
                    ],
                    resources=["*"],
                    conditions={
                        "ArnEquals": {"ecs:cluster": self.ecs_cluster.cluster_arn}
                    },
                ),
                iam.PolicyStatement(
                    actions=["iam:PassRole"],
                    resources=[
                        f"arn:{cdk.Aws.PARTITION}:iam::{cdk.Aws.ACCOUNT_ID}:role/{self.cluster_name}-ad-sync-task-role",
                    ],
                ),
            ],
        )
        terminate_ad_sync_ecs_task_role.attach_inline_policy(
            terminate_ad_sync_ecs_task_policy
        )
        self.add_common_tags(terminate_ad_sync_ecs_task_role)

        terminate_ad_sync_ecs_task_lambda = _lambda.Function(
            self.nested_stack,
            id="terminate-ad-sync-ecs-task",
            function_name=lambda_name,
            description=f"Custom lambda to terminate AD sync ECS task before deleting AD sync ECS cluster",
            environment={
                "environment_name": self.cluster_name,
            },
            timeout=Duration.seconds(300),
            role=terminate_ad_sync_ecs_task_role,
            runtime=RES_COMMON_LAMBDA_RUNTIME,
            **InfraUtils.get_handler_and_code_for_function(handler.handler),
            layers=[self.lambda_layer],
        )
        self.add_common_tags(terminate_ad_sync_ecs_task_lambda)

        terminate_ad_sync_ecs_task_custom_resource = cdk.CustomResource(
            self.nested_stack,
            id="terminate-ad-sync-ecs-task-custom-resource",
            service_token=terminate_ad_sync_ecs_task_lambda.function_arn,
            removal_policy=cdk.RemovalPolicy.DESTROY,
            resource_type="Custom::TerminateADSyncECSTask",
        )

        terminate_ad_sync_ecs_task_custom_resource.node.add_dependency(
            terminate_ad_sync_ecs_task_policy
        )
        terminate_ad_sync_ecs_task_custom_resource.node.add_dependency(self.ecs_cluster)
        terminate_ad_sync_ecs_task_custom_resource.node.add_dependency(
            self.ad_sync_lock_table
        )

    # Create a custom lambda to store AD sync resources in DDB
    def build_ad_sync_resources_populator(self) -> None:
        lambda_name = f"{self.cluster_name}-ad-sync-resources-populator"
        ad_sync_resources_populator_role = iam.Role(
            self.nested_stack,
            id="ad-sync-resources-populator-role",
            role_name=f"{lambda_name}-role",
            assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
            description=f"{lambda_name}-role",
        )

        ad_sync_resources_populator_policy = iam.Policy(
            self.nested_stack,
            id="ad-sync-resources-populator-policy",
            policy_name=f"{lambda_name}-policy",
            statements=[
                iam.PolicyStatement(
                    actions=["logs:CreateLogGroup"],
                    sid="CloudWatchLogsPermissions",
                    resources=["*"],
                ),
                iam.PolicyStatement(
                    actions=[
                        "logs:CreateLogStream",
                        "logs:PutLogEvents",
                        "logs:DeleteLogStream",
                    ],
                    sid="CloudWatchLogStreamPermissions",
                    resources=["*"],
                ),
                iam.PolicyStatement(
                    actions=[
                        "dynamodb:PutItem",
                    ],
                    sid="ClusterSettingsTablePermissions",
                    resources=[
                        InfraUtils.get_ddb_table_arn(
                            self.cluster_name,
                            cluster_settings.CLUSTER_SETTINGS_TABLE_NAME,
                        ),
                    ],
                ),
            ],
        )
        ad_sync_resources_populator_role.attach_inline_policy(
            ad_sync_resources_populator_policy
        )
        self.add_common_tags(ad_sync_resources_populator_role)

        ad_sync_resources_populator_lambda = _lambda.Function(
            self.nested_stack,
            id="ad-sync-resources-populator",
            function_name=lambda_name,
            description=f"Custom lambda to store AD sync resources in DDB",
            environment={
                **self.build_ad_sync_resources_populator_environment_varaibles(),
                ENVIRONMENT_NAME_KEY: self.cluster_name,
            },
            timeout=Duration.seconds(300),
            role=ad_sync_resources_populator_role,
            runtime=RES_COMMON_LAMBDA_RUNTIME,
            **InfraUtils.get_handler_and_code_for_function(
                ad_sync_resources_populator_handler.handler
            ),
            layers=[self.lambda_layer],
        )
        self.add_common_tags(ad_sync_resources_populator_lambda)

        ad_sync_resources_populator_custom_resource = cdk.CustomResource(
            self.nested_stack,
            id="ad-sync-resources-populator-custom-resource",
            service_token=ad_sync_resources_populator_lambda.function_arn,
            removal_policy=cdk.RemovalPolicy.DESTROY,
            resource_type="Custom::ADSyncResourcesPopulator",
        )

        ad_sync_resources_populator_custom_resource.node.add_dependency(
            self.ad_sync_security_group
        )
        ad_sync_resources_populator_custom_resource.node.add_dependency(
            self.ecs_cluster
        )
        ad_sync_resources_populator_custom_resource.node.add_dependency(
            self.task_definition
        )
        ad_sync_resources_populator_custom_resource.node.add_dependency(
            ad_sync_resources_populator_policy
        )

    def build_ad_sync_resources_populator_environment_varaibles(self) -> Dict[str, Any]:
        return {
            "ad_sync_security_group_id": self.ad_sync_security_group.security_group_id,
            "ad_sync_task_cluster": self.ecs_cluster.cluster_name,
            "ad_sync_task_definition": self.task_definition.family,
        }
