from aws_cdk import core, aws_iam as iam, aws_events as events, aws_events_targets as targets


class EnterpriseAwsSsoManagementStack(core.Stack):
    def __init__(
        self, scope: core.Construct, construct_id: str, full_deployment: bool, **kwargs
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)

        ## Getting parameters and setting defaults
        context: dict = self.node.try_get_context("enterprise_sso")

        enterprise_sso_exec_account_id: str = context.get("enterprise_sso_exec_account_id")
        enterprise_sso_read_only_role: str = context.get(
            "enterprise_sso_management_read_only_role",
            "assignment-management-read-only-role",
        )
        enterprise_sso_assignment_management_role: str = context.get(
            "enterprise_sso_management_role", "assignment-management-role"
        )
        target_event_bus_name: str = context.get("target_event_bus_name", "enterprise-aws-sso")
        target_event_bus_region: str = context.get("target_event_bus_region", self.region)

        if full_deployment or (self.region != "us-east-1" and not full_deployment):
            ### Permission management ###

            ## Read only role for assignment definition handler function ##
            identitystore_policy = iam.PolicyDocument(
                statements=[
                    iam.PolicyStatement(
                        actions=[
                            "identitystore:DescribeUser",
                            "identitystore:ListUsers",
                            "identitystore:DescribeGroup",
                            "identitystore:ListGroups",
                        ],
                        effect=iam.Effect.ALLOW,
                        resources=["*"],
                    )
                ]
            )

            organizations_policy = iam.PolicyDocument(
                statements=[
                    iam.PolicyStatement(
                        actions=["organizations:DescribeOrganizationalUnit", "tag:GetResources"],
                        effect=iam.Effect.ALLOW,
                        resources=["*"],
                    )
                ]
            )

            self.management_enterprise_sso_read_only_role = iam.Role(
                self,
                "EnterpriseAWSSSOReadOnlyRole",
                role_name=enterprise_sso_read_only_role,
                inline_policies={
                    "identitystore-readonly": identitystore_policy,
                    "organizations-readonly": organizations_policy,
                },
                managed_policies=[iam.ManagedPolicy.from_aws_managed_policy_name("AWSSSOReadOnly")],
                assumed_by=iam.ArnPrincipal(
                    f"arn:aws:iam::{enterprise_sso_exec_account_id}:role/{enterprise_sso_read_only_role}"
                ),
            )

            ## Assignment management role for assignment execution function ##
            assignment_management_policy = iam.PolicyDocument(
                statements=[
                    iam.PolicyStatement(
                        actions=[
                            "sso:CreateAccountAssignment",
                            "sso:ListPermissionSetsProvisionedToAccount",
                            "sso:ListInstances",
                            "sso:DeleteAccountAssignment",
                        ],
                        effect=iam.Effect.ALLOW,
                        resources=["*"],
                    ),
                    iam.PolicyStatement(
                        sid="IAMListPermissions",
                        actions=["iam:ListRoles", "iam:ListPolicies"],
                        effect=iam.Effect.ALLOW,
                        resources=["*"],
                    ),
                    iam.PolicyStatement(
                        sid="AccessToSSOProvisionedRoles",
                        actions=[
                            "iam:AttachRolePolicy",
                            "iam:CreateRole",
                            "iam:DeleteRole",
                            "iam:DeleteRolePolicy",
                            "iam:DetachRolePolicy",
                            "iam:GetRole",
                            "iam:ListAttachedRolePolicies",
                            "iam:ListRolePolicies",
                            "iam:PutRolePolicy",
                            "iam:UpdateRole",
                            "iam:UpdateRoleDescription",
                        ],
                        effect=iam.Effect.ALLOW,
                        resources=["arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/*"],
                    ),
                    iam.PolicyStatement(
                        actions=["iam:GetSAMLProvider"],
                        effect=iam.Effect.ALLOW,
                        resources=["arn:aws:iam::*:saml-provider/AWSSSO_*_DO_NOT_DELETE"],
                    ),
                ]
            )

            self.management_enterprise_sso_assignment_management_role = iam.Role(
                self,
                "EnterpriseAWSSSOAssignmentManagementRole",
                role_name=enterprise_sso_assignment_management_role,
                inline_policies={
                    "enterprise-sso-assignment-management": assignment_management_policy
                },
                assumed_by=iam.ArnPrincipal(
                    f"arn:aws:iam::{enterprise_sso_exec_account_id}:role/{enterprise_sso_assignment_management_role}"
                ),
            )

        if (not full_deployment and self.region == "us-east-1") or full_deployment:
            ### Event bus configuration ###
            enterprise_sso_eventbus = events.EventBus.from_event_bus_arn(
                self,
                "enterpriseawsssoEventbus",
                event_bus_arn=f"arn:aws:events:{target_event_bus_region}:{enterprise_sso_exec_account_id}:event-bus/{target_event_bus_name}",
            )

            self.organizations_events_forwarding_rule = events.Rule(
                self,
                "OrganizationsEventsRule",
                description="Forward Organizations events to enterprise-aws-sso",
                event_pattern=events.EventPattern(
                    detail={
                        "eventName": [
                            "CreateAccountResult",
                            "MoveAccount",
                            "TagResource",
                            "UntagResource",
                        ]
                    },
                    detail_type=["AWS Service Event via CloudTrail", "AWS API Call via CloudTrail"],
                    source=["aws.organizations"],
                ),
                targets=[targets.EventBus(enterprise_sso_eventbus)],
            )

            # AWS SSO Events
            self.sso_events_forwarding_rule = events.Rule(
                self,
                "AWSSSOEventsRule",
                description="Forward CT events to enterprise-aws-sso",
                event_pattern=events.EventPattern(
                    detail={"eventName": ["CreatePermissionSet", "DeletePermissionSet"]},
                    detail_type=["AWS Service Event via CloudTrail", "AWS API Call via CloudTrail"],
                    source=["aws.sso"],
                ),
                targets=[targets.EventBus(enterprise_sso_eventbus)],
            )