provider "aws" {
  region = var.aws_region
}

terraform {
  backend "s3" {
    bucket  = "dev-orcd-terraform-state"
    key     = "dev/streamlit-audience/etl/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

data "aws_caller_identity" "current" {}

data "aws_s3_bucket" "selected" {
  bucket = var.application_bucket
}

resource "aws_security_group" "streamlit_audience_etl_security_group" {
  name        = "${var.environment}-${var.service_name}-security-group"
  description = "Security group for ${var.environment}-${var.service_name} Batch job"
  vpc_id      = "vpc-34dbfd51"

  tags = local.tags
}

resource "aws_security_group_rule" "streamlit_audience_etl_security_group_egress_rule" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.streamlit_audience_etl_security_group.id
}

# Create policy to access S3 bucket from ETL process
data "aws_iam_policy_document" "streamlit_audience_etl_s3_policy_document" {
  statement {
    actions = [
      "s3:GetObject",
      "s3:PutObject",
    ]
    resources = [
      "${data.aws_s3_bucket.selected.arn}/*"
    ]
  }

  statement {
    actions = [
      "s3:GetBucketLocation",
      "s3:ListBucket",
    ]
    resources = [
      data.aws_s3_bucket.selected.arn
    ]
  }
}

resource "aws_iam_policy" "streamlit_audience_etl_s3_policy" {
  name        = "S3-${var.environment}-${var.service_name}-RW-policy"
  description = "RW access to the ${var.application_bucket} bucket"
  policy      = data.aws_iam_policy_document.streamlit_audience_etl_s3_policy_document.json
}

data "aws_iam_policy_document" "streamlit_audience_job_assume_role_policy_document" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type = "Service"
      identifiers = [
        "ecs.amazonaws.com",
        "ec2.amazonaws.com",
        "ecs-tasks.amazonaws.com"
      ]
    }
  }
}

data "aws_iam_policy_document" "secrets_manager_policy" {
  statement {
    actions = [
      "secretsmanager:GetResourcePolicy",
      "secretsmanager:GetSecretValue",
      "secretsmanager:DescribeSecret",
      "secretsmanager:ListSecretVersionIds",
    ]

    resources = [
      "arn:aws:secretsmanager:*:*:secret:dev/streamlit-audience-etl/",
      "arn:aws:secretsmanager:*:*:secret:dev/streamlit-audience-etl/*",
    ]
  }

  statement {
    actions = [
      "secretsmanager:GetRandomPassword",
    ]

    resources = [
      "*",
    ]
  }
}
#
data "aws_iam_policy_document" "streamlit_audience_events_assume_role_policy_document" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type = "Service"
      identifiers = [
        "events.amazonaws.com"
      ]
    }
  }
}

#  Policy for starting invoking batch job queue initiated by a CloudWatch rule.
data "aws_iam_policy_document" "invoke_batch_job_queue" {
  statement {
    actions = [
      "batch:SubmitJob",
    ]
    resources = [
      "arn:aws:batch:${var.aws_region}:${data.aws_caller_identity.current.account_id}:job-definition/${aws_batch_job_definition.streamlit_audience_etl_job_definition.name}",
      aws_batch_job_queue.streamlit_audience_etl_queue.arn,
    ]
  }
}

resource "aws_iam_policy" "streamlit_audience_etl_submit_batch_queue" {
  name   = "Batch-${var.environment}-${var.service_name}-submit-policy"
  policy = data.aws_iam_policy_document.invoke_batch_job_queue.json
}

# CloudWatch event rule role for starting execution
resource "aws_iam_role" "execute_batch_job_role" {
  name               = "${var.environment}-${var.service_name}-trigger-batch-job"
  assume_role_policy = data.aws_iam_policy_document.streamlit_audience_events_assume_role_policy_document.json
}

resource "aws_iam_role_policy_attachment" "attach-batch-invocation" {
  role       = aws_iam_role.execute_batch_job_role.name
  policy_arn = aws_iam_policy.streamlit_audience_etl_submit_batch_queue.arn
}

# Event rule for triggering AWS Batch job.
resource "aws_cloudwatch_event_rule" "etl_batch_event_rule" {
  name                = "${var.environment}-${var.service_name}-trigger-batch-job-rule"
  description         = "The CloudWatch event rule for triggering AWS Batch job"
  schedule_expression = "cron(1 6 5 * ? *)"
  role_arn            = aws_iam_role.execute_batch_job_role.arn
}

# Event target
resource "aws_cloudwatch_event_target" "etl_batch_target" {
  rule     = aws_cloudwatch_event_rule.etl_batch_event_rule.name
  role_arn = aws_iam_role.execute_batch_job_role.arn
  arn      = aws_batch_job_queue.streamlit_audience_etl_queue.arn

  batch_target {
    job_definition = aws_batch_job_definition.streamlit_audience_etl_job_definition.name
    job_name       = "streamlit_etl_batch_schedule"
    job_attempts   = 1
  }
}

# Secrets manager policy for job role
resource "aws_iam_policy" "streamlit_audience_etl_secret_policy" {
  name   = "SecretsManager-${var.environment}-${var.service_name}-policy"
  policy = data.aws_iam_policy_document.secrets_manager_policy.json
}

resource "aws_iam_role" "streamlit_audience_job_role" {
  name               = "${var.environment}-${var.service_name}-job-role"
  assume_role_policy = data.aws_iam_policy_document.streamlit_audience_job_assume_role_policy_document.json
}

resource "aws_iam_role_policy_attachment" "streamlit_audience_job_s3_bucket_policy_attachment" {
  role       = aws_iam_role.streamlit_audience_job_role.name
  policy_arn = aws_iam_policy.streamlit_audience_etl_s3_policy.arn
}

resource "aws_iam_role_policy_attachment" "streamlit_audience_job_ecs_policy_attachment" {
  role       = aws_iam_role.streamlit_audience_job_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

# Attach secrets manager policy to task role
resource "aws_iam_role_policy_attachment" "streamlit_audience_job_secrets_manager_policy_attachment" {
  role       = aws_iam_role.streamlit_audience_job_role.name
  policy_arn = aws_iam_policy.streamlit_audience_etl_secret_policy.arn
}

# Compute environment
resource "aws_batch_compute_environment" "streamlit_audience_etl_batch_compute" {
  compute_environment_name = "${var.environment}-${var.service_name}-compute"

  compute_resources {
    max_vcpus = 8

    security_group_ids = [aws_security_group.streamlit_audience_etl_security_group.id] # required
    subnets            = var.vpc_subnet_ids                                            # required

    type = "FARGATE"
  }
  # seems that all compute environments share this single role
  service_role = "arn:aws:iam::103233932089:role/service-role/AWSBatchServiceRole"
  type         = "MANAGED"

  tags = local.tags
}

# Job queue
resource "aws_batch_job_queue" "streamlit_audience_etl_queue" {
  name     = "${var.environment}-${var.service_name}-batch-queue"
  state    = "ENABLED"
  priority = 1
  compute_environments = [
    aws_batch_compute_environment.streamlit_audience_etl_batch_compute.arn
  ]

  tags = local.tags
}

# Job definition
resource "aws_batch_job_definition" "streamlit_audience_etl_job_definition" {
  name = "${var.environment}-${var.service_name}-job-definition"
  type = "container"
  platform_capabilities = [
    "FARGATE",
  ]

  timeout {
    attempt_duration_seconds = 7200 # 2 hours
  }

  tags = local.tags

  container_properties = <<CONTAINER_PROPERTIES
{
  "image": "103233932089.dkr.ecr.us-east-1.amazonaws.com/streamlit-etl:latest",
  "fargatePlatformConfiguration": {
    "platformVersion": "LATEST"
  },
  "resourceRequirements": [
    {"type": "VCPU", "value": "8"},
    {"type": "MEMORY", "value": "61440"}
  ],
  "executionRoleArn": "${aws_iam_role.streamlit_audience_job_role.arn}",
  "jobRoleArn": "${aws_iam_role.streamlit_audience_job_role.arn}",
  "environment": [
    {"name": "SNOWFLAKE_ACCOUNT", "value": "${var.snowflake_account}"},
    {"name": "SNOWFLAKE_DATABASE", "value": "${var.snowflake_database}"},
    {"name": "SNOWFLAKE_SCHEMA", "value": "${var.snowflake_schema}"},
    {"name": "SNOWFLAKE_WAREHOUSE", "value": "${var.snowflake_warehouse}"},
    {"name": "SNOWFLAKE_ROLE", "value": "${var.snowflake_role}"},
    {"name": "SNOWFLAKE_USER", "value": "${var.snowflake_user}"}
  ],
  "secrets": [
    {
      "name": "SNOWFLAKE_PRIVATE_KEY_PASSPHRASE",
      "valueFrom": "arn:aws:secretsmanager:us-east-1:103233932089:secret:dev/streamlit-audience-etl/SNOWFLAKE_PRIVATE_KEY_PASSPHRASE-jDzV2W"
    },
    {
      "name": "SNOWFLAKE_PRIVATE_KEY",
      "valueFrom": "arn:aws:secretsmanager:us-east-1:103233932089:secret:dev/streamlit-audience-etl/SNOWFLAKE_PRIVATE_KEY-oFSMjY"
    }
  ]
}
CONTAINER_PROPERTIES
}

module "streamlit_audience_etl_secrets" {
  source   = "git@github.com:theorchard/terraform-secrets-manager.git//?ref=1.5.1"
  for_each = toset(var.secrets_manager_snowflake_secret_names)

  application_family = var.application_family
  environment        = var.environment
  service_name       = var.service_name
  secret_name        = each.value
}
