#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import aws_cdk as cdk
from constructs import Construct
import sys
from aws_cdk import (
    aws_iam as iam,
    aws_ecs as ecs,
    aws_logs as logs
)
from aws_cdk.aws_ecr_assets import DockerImageAsset
import json
from jinja2 import Template


class TaskDefinitionStack(cdk.Stack):
    def __init__(
        self, scope: Construct, construct_id: str, env, props, **kwargs
    ) -> None:
        super().__init__(scope, construct_id, env=env, **kwargs)
        try:

            self.fargate_execution_role = iam.Role(
                self,
                "GitlabExecutionRole",
                assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
                managed_policies=[
                    iam.ManagedPolicy.from_aws_managed_policy_name(
                        "service-role/AmazonECSTaskExecutionRolePolicy"
                    )
                ],
            )
        
            self.fargate_task_role = iam.Role(
                self,
                "GitlabTaskRole",
                assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
                managed_policies=[
                    iam.ManagedPolicy.from_aws_managed_policy_name(policy) for policy in props.get("managed_policies", [])
                ]
            )
    
            try:
                task_policies_template = props.get("iam_policy_template", "")
                with open(task_policies_template) as f:
                    j2_template = Template(f.read())
                rendered_template = j2_template.render(
                    region=self.region, account=self.account
                )
                task_policies = json.loads(rendered_template)
                self.fargate_task_role_policies = iam.Policy(
                    self,
                    "taskPolicy",
                    document=iam.PolicyDocument.from_json(task_policies),
                )
                self.fargate_task_role.attach_inline_policy(
                    self.fargate_task_role_policies
                )
            except IOError:
                print("No task policies template provided.")
            # Add Fargate task definition
            default_docker_image = DockerImageAsset(
                self,
                props.get("docker_image_name"),
                directory=f'./docker_images/{props.get("docker_image_name")}',
                build_args={
                    "GITLAB_RUNNER_VERSION": props.get("gitlab_runner_version") 
                }
            )

            # Create LogGroup
            self.log_group = logs.LogGroup(self,
                                           id="LogGroup",
                                           log_group_name=props.get(
                                               "log_group_name", f'/Gitlab/TaskDefinitions/{props.get("docker_image_name")}/'),
                                           removal_policy=cdk.RemovalPolicy.DESTROY,
                                           retention=logs.RetentionDays.ONE_DAY,
                                           )

            awslogs_driver = ecs.CfnTaskDefinition.LogConfigurationProperty(
                log_driver="awslogs",
                options={
                    "awslogs-group": self.log_group.log_group_name,
                    "awslogs-region": self.region,
                    "awslogs-stream-prefix": "fargate",
                },
            )
            port_mappings = [
                ecs.CfnTaskDefinition.PortMappingProperty(container_port=22)
            ]
            ci_coordinator = ecs.CfnTaskDefinition.ContainerDefinitionProperty(
                name="ci-coordinator",
                image=default_docker_image.image_uri,
                port_mappings=port_mappings,
                log_configuration=awslogs_driver,
            )
            self.fargate_task_definition = ecs.CfnTaskDefinition(
                self,
                f'{props.get("docker_image_name")}TaskDefinition',
                family=f'{props.get("docker_image_name")}',
                cpu=str(props.get("task_definition_cpu", 256)),
                memory=str(props.get("task_definition_memory", 512)),
                network_mode="awsvpc",
                task_role_arn=self.fargate_task_role.role_arn,
                execution_role_arn=self.fargate_execution_role.role_arn,
                container_definitions=[ci_coordinator],
            )

            self.output_props = props.copy()
            self.output_props["fargate_task_definition"] = self.fargate_task_definition

        except:
            print("Unexpected error:", sys.exc_info()[0])
            raise

    @property
    def outputs(self):
        return self.output