# Assume role policy for Cloudwatch events
data "aws_iam_policy_document" "cloudwatch_event_assume_role_policy" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type = "Service"

      identifiers = [
        "events.amazonaws.com",
      ]
    }
  }
}

data "aws_iam_policy_document" "cloudwatch_event_policy" {
  statement {
    actions = [
      "iam:PassRole",
    ]

    resources = [
      aws_iam_role.fargate_task_execution_role.arn,
      aws_iam_role.fargate_task_role.arn,
    ]
  }

  statement {
    actions = [
      "ecs:RunTask",
    ]

    resources = [
      "arn:aws:ecs:${var.aws_region}:*:task-definition/${var.environment}-${var.service_name}:*",
    ]
  }

  statement {
    effect = "Allow"
    actions = [
      "ecs:TagResource",
    ]
    resources = [
      "arn:aws:ecs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:task/${local.ecs_cluster_name}/*",
    ]
  }
}

# Cloudwatch events role
resource "aws_iam_role" "cloudwatch_event_role" {
  count                = var.cloudwatch_event_enabled ? 1 : 0
  name                 = "${var.environment}-${var.service_name}-cloudwatch-event-role"
  assume_role_policy   = data.aws_iam_policy_document.cloudwatch_event_assume_role_policy.json
  permissions_boundary = local.permissions_boundary_arn

  tags = local.combined_resource_tags
}

# Policy to allow Cloudwatch events to run task
resource "aws_iam_role_policy" "cloudwatch_event_policy" {
  count  = var.cloudwatch_event_enabled ? 1 : 0
  name   = "${var.environment}-${var.service_name}-cloudwatch-event-policy"
  role   = aws_iam_role.cloudwatch_event_role[count.index].id
  policy = data.aws_iam_policy_document.cloudwatch_event_policy.json
}

# Cloudwatch event rule
resource "aws_cloudwatch_event_rule" "fargate_run_schedule" {
  count               = var.cloudwatch_event_enabled ? 1 : 0
  name                = "${var.environment}-${var.service_name}-fargate-event"
  schedule_expression = var.cloudwatch_event_schedule
  description         = "Run ${var.environment}-${var.service_name} according to schedule"

  tags = local.combined_resource_tags
}

# Fargate task target for Cloudwatch event
resource "aws_cloudwatch_event_target" "fargate_event_target" {
  count     = var.cloudwatch_event_enabled ? 1 : 0
  rule      = aws_cloudwatch_event_rule.fargate_run_schedule[0].name
  target_id = "${var.environment}_${var.service_name}_fargate_event_target"
  arn       = local.ecs_cluster_arn
  role_arn  = aws_iam_role.cloudwatch_event_role[0].arn

  ecs_target {
    task_count          = var.cloudwatch_event_task_count_per_event
    task_definition_arn = aws_ecs_task_definition.fargate_task.arn
    launch_type         = var.ecs_launch_type
    platform_version    = local.platform_version

    dynamic "network_configuration" {
      for_each = var.task_type == "external_worker" ? [] : [1]
      content {
        security_groups  = concat(var.custom_security_group_ids, [aws_security_group.task_security_group[0].id])
        subnets          = var.fargate_service_subnets
        assign_public_ip = var.assign_public_ip
      }
    }

    tags = local.combined_resource_tags
  }

  # Allow external changes (e.g. task definition updates) without Terraform caring
  lifecycle {
    ignore_changes = [ecs_target[0].task_definition_arn]
  }
}

resource "aws_cloudwatch_event_rule" "fargate_stopped_task_event_rule" {
  count = var.stopped_task_monitoring_enabled ? 1 : 0

  name          = "${var.environment}-${var.service_name}-stopped-task-rule"
  description   = "Triggered when an Amazon ECS Task is stopped"
  event_pattern = local.cw_event_pattern
}

data "aws_ssm_parameter" "datadog_api_destination_arn_parameter" {
  count = var.stopped_task_monitoring_enabled || var.task_placement_failure_alert_enabled ? 1 : 0

  name = "/events/destination-api/datadog"
}

data "aws_iam_role" "datadog_api_event_target_destination_role" {
  count = var.stopped_task_monitoring_enabled || var.task_placement_failure_alert_enabled ? 1 : 0

  name = "cw-datadog-api-destination-role"
}

resource "aws_cloudwatch_event_target" "stopped_task_event_target" {
  count = var.stopped_task_monitoring_enabled ? 1 : 0

  target_id = "datadog"
  rule      = aws_cloudwatch_event_rule.fargate_stopped_task_event_rule[0].name
  arn       = data.aws_ssm_parameter.datadog_api_destination_arn_parameter[0].value
  role_arn  = data.aws_iam_role.datadog_api_event_target_destination_role[0].arn

  input_transformer {
    input_paths = {
      "detail" = "$.detail"
    }
    input_template = <<EOT
{
  "message": <detail>,
  "ddsource": "eventbridge",
  "service": "${var.environment}-${var.service_name}",
  "ddtags": "environment:${var.environment},service_name:${var.service_name},aws_service:ecs,event:stopped_task"
}
EOT
  }
}


resource "aws_cloudwatch_event_rule" "task_placement_failure_event_rule" {
  count = var.task_placement_failure_alert_enabled ? 1 : 0

  name        = "${var.environment}-${var.service_name}-placement-failure-rule"
  description = "Triggered when ECS task placement fails"
  event_pattern = jsonencode({
    source      = ["aws.ecs"],
    detail-type = ["ECS Deployment State Changee"],
    detail = {
      eventName  = ["SERVICE_TASK_PLACEMENT_FAILURE"]
      clusterArn = [local.ecs_cluster_arn]
      reason     = ["RESOURCE:FARGATE"]
    }
  })

  tags = local.combined_resource_tags
}

resource "aws_cloudwatch_event_target" "task_placement_failure_event_target" {
  count = var.task_placement_failure_alert_enabled ? 1 : 0

  target_id = "datadog"
  rule      = aws_cloudwatch_event_rule.task_placement_failure_event_rule[0].name
  arn       = data.aws_ssm_parameter.datadog_api_destination_arn_parameter[0].value
  role_arn  = data.aws_iam_role.datadog_api_event_target_destination_role[0].arn

  input_transformer {
    input_paths = {
      "detail" = "$.detail"
    }
    input_template = <<EOT
{
  "message": <detail>,
  "ddsource": "eventbridge",
  "service": "${var.environment}-${var.service_name}",
  "ddtags": "environment:${var.environment},service_name:${var.service_name},aws_service:ecs,event:task_placement_failure"
}
EOT
  }
}
