module "default_tags" {
  source             = "git@github.com:theorchard/terraform-default-tags.git//?ref=2.0.0"
  environment        = var.environment
  application_family = var.application_family
  service_name       = var.service_name
  team_name          = var.team_name
}

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = module.default_tags.tags
  }
}

# Terraform backends cannot contain interpolations
terraform {
  backend "s3" {
    bucket  = "orcd-terraform-state"
    key     = "prod/vector/generate_encoding_orders/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

module "vpc_info" {
  source      = "git@github.com:theorchard/terraform-vpc-info.git//?ref=3.1.0"
  environment = var.environment
}

data "aws_caller_identity" "current" {}

# Policy for read-only access to the S3 bucket
data "aws_iam_policy" "s3_configs_read_only_policy" {
  name = "S3-${var.environment}-${var.config_service_name}-RO"
}

# Policy for KMS access to encrypted config objects in the S3 bucket
data "aws_iam_policy" "orchard_repo_cron_worker_kms_policy" {
  name = "KMS-${var.environment}-${var.config_service_name}-policy"
}

module "generate_encoding_order_queues" {
  source   = "git@github.com:theorchard/terraform-sqs.git//?ref=2.4.1"
  for_each = local.service_name_to_queue_map

  environment                    = var.environment
  custom_queue_name              = each.value["queue_name"]
  application_family             = var.application_family
  sqs_message_retention_seconds  = 345600
  sqs_max_message_size           = 1048576
  sqs_receive_wait_time_seconds  = 0
  sqs_delay_seconds              = 0
  sqs_visibility_timeout_seconds = 30
  additional_tags = {
    "vector_worker_type" : "generate_encoding_orders"
  }
}

module "generate_encoding_order_sns_topics" {
  source   = "git@github.com:theorchard/terraform-sns.git//?ref=3.0.0"
  for_each = local.service_name_to_queue_map

  environment              = var.environment
  sns_topic_name           = each.value["topic_name"]
  application_family       = var.application_family
  sns_subscription_enabled = false
}

data "aws_elasticache_replication_group" "split_synchronizer_redis_cache" {
  replication_group_id = "${var.environment}-split-synchronizer"
}

module "generate_encoding_order_fargate_environment" {
  for_each = local.service_name_to_queue_map
  source   = "git@github.com:theorchard/terraform-fargate.git//?ref=6.5.0"

  providers = {
    aws.dns = aws
  }

  environment                        = var.environment
  service_name                       = each.value["service_name"]
  secrets_manager_service_name       = var.m2m_service_name
  aws_region                         = var.aws_region
  application_family                 = var.application_family
  non_ecr_image                      = "086679231553.dkr.ecr.${var.aws_region}.amazonaws.com/${var.config_service_name}:latest"
  task_type                          = "worker"
  health_check_command               = "pgrep php"
  deployment_minimum_healthy_percent = "100"
  autoscaling_cpu_policy_enabled     = false
  autoscaling_memory_policy_enabled  = false
  desired_task_count                 = 0
  minimum_capacity                   = var.minimum_capacity
  maximum_capacity                   = var.maximum_capacity
  task_cpu                           = 2048
  task_memory                        = 4096
  container_port                     = 8080
  health_check_grace_period_seconds  = 300
  container_start_period_seconds     = 300
  target_deregistration_delay        = 300
  task_protection_policy_enabled     = true
  vpc_id                             = module.vpc_info.vpc_id
  fargate_service_subnets            = concat(["subnet-067a6b45b079d7296"], module.vpc_info.default_private_subnet_ids)
  iam_managed_policy_attachments = [
    data.aws_iam_policy.orchard_repo_cron_worker_kms_policy.arn,
    data.aws_iam_policy.s3_configs_read_only_policy.arn,
  ]

  environment_variables = [
    {
      Environment = var.environment
    },
    {
      APPLICATION_ENV = "production"
    },
    {
      DD_TRACE_ANALYTICS_ENABLED = "true"
    },
    {
      DD_TRACE_APP_NAME = each.value["service_name"]
    },
    {
      DD_TRACE_GLOBAL_TAGS = "env:${var.environment}"
    },
    {
      PATH_FROM_REPO_ROOT_OF_PHP_SCRIPT_TO_RUN = "scripts/encodingorder/generate_encoding_orders.php"
    },
    {
      SCRIPT_ARGUMENTS = "-n ${each.value["queue_name"]} -m ${each.value["number_of_messages"]}"
    },
    {
      PHP_DISPLAY_ERRORS = "false"
    },
    {
      S3_CONFIG_LOCATION = "${var.config_s3_bucket}/${var.config_service_name}/${var.environment}"
    },
    {
      LC_ALL = "en_US.UTF-8"
    },
    {
      LANG = "en_US.UTF-8"
    },
    {
      LANGUAGE = "en_US.UTF-8"
    },
    {
      SENTRY_DSN = "https://c0e8157de78d448ca46774ca98f7c094@o22178.ingest.us.sentry.io/67618"
    },
    {
      SPLITIO_REDIS_HOST = data.aws_elasticache_replication_group.split_synchronizer_redis_cache.primary_endpoint_address
    },
    {
      SPLITIO_REDIS_PORT = data.aws_elasticache_replication_group.split_synchronizer_redis_cache.port
    },
  ]
  secrets = [
    {
      SPLITIO_API_KEY = "${var.environment}/split/API_KEY"
    },
  ]
}

data "aws_iam_role" "fargate_autoscaling_role" {
  name = "AWSServiceRoleForApplicationAutoScaling_ECSService"
}

# Configure SQS metric-based autoscaling
resource "aws_appautoscaling_target" "scaling_target" {
  for_each           = local.service_name_to_queue_map
  service_namespace  = "ecs"
  resource_id        = "service/${var.environment}-${each.value["service_name"]}/${var.environment}-${each.value["service_name"]}"
  scalable_dimension = "ecs:service:DesiredCount"
  role_arn           = data.aws_iam_role.fargate_autoscaling_role.arn
  min_capacity       = var.minimum_capacity
  max_capacity       = var.maximum_capacity

  depends_on = [module.generate_encoding_order_fargate_environment]
}

# Configure alarm based on number of messages in specified SQS queue being greater than 0
resource "aws_cloudwatch_metric_alarm" "sqs_queue_more_than_zero_visible_messages" {
  for_each          = local.service_name_to_queue_map
  alarm_name        = "SQS-${var.environment}-${each.value["service_name"]}-visible-message-alarm"
  alarm_description = "SQS-${var.environment}-${each.value["service_name"]}-visible-message-alarm"
  namespace         = "AWS/SQS"
  metric_name       = "ApproximateNumberOfMessagesVisible"
  statistic         = "Maximum"

  dimensions = {
    QueueName = each.value["queue_name"]
  }

  comparison_operator = "GreaterThanThreshold"
  threshold           = 0
  period              = 60
  evaluation_periods  = 1

  alarm_actions             = [aws_appautoscaling_policy.scale_up_policy[each.key].arn]
  insufficient_data_actions = []
}

# Configure alarm based on number of messages in specified SQS queue being 0. This is added
# as a discrete resource in order to change the evaluation period before which scaling activities occur
resource "aws_cloudwatch_metric_alarm" "sqs_queue_zero_visible_messages" {
  for_each          = local.service_name_to_queue_map
  alarm_name        = "SQS-${var.environment}-${each.value["service_name"]}-zero-visible-messages-alarm"
  alarm_description = "SQS-${var.environment}-${each.value["service_name"]}-zero-visible-messages-alarm"
  namespace         = "AWS/SQS"
  metric_name       = "ApproximateNumberOfMessagesVisible"
  statistic         = "Maximum"

  dimensions = {
    QueueName = each.value["queue_name"]
  }

  comparison_operator = "LessThanOrEqualToThreshold"
  threshold           = 0
  period              = 60
  evaluation_periods  = 5

  alarm_actions             = [aws_appautoscaling_policy.scale_down_policy[each.key].arn]
  insufficient_data_actions = []
}

resource "aws_appautoscaling_policy" "scale_up_policy" {
  for_each           = local.service_name_to_queue_map
  name               = "${var.environment}-${each.value["service_name"]}-sqs-scale-up-policy"
  policy_type        = "StepScaling"
  resource_id        = aws_appautoscaling_target.scaling_target[each.key].resource_id
  scalable_dimension = aws_appautoscaling_target.scaling_target[each.key].scalable_dimension
  service_namespace  = aws_appautoscaling_target.scaling_target[each.key].service_namespace

  step_scaling_policy_configuration {
    adjustment_type         = "ChangeInCapacity"
    cooldown                = var.scale_up_cooldown_period
    metric_aggregation_type = "Maximum"

    step_adjustment {
      metric_interval_lower_bound = 0
      scaling_adjustment          = var.scale_up_adjustment
    }
  }
}

resource "aws_appautoscaling_policy" "scale_down_policy" {
  for_each           = local.service_name_to_queue_map
  name               = "${var.environment}-${each.value["service_name"]}-sqs-scale-down-policy"
  resource_id        = aws_appautoscaling_target.scaling_target[each.key].resource_id
  scalable_dimension = aws_appautoscaling_target.scaling_target[each.key].scalable_dimension
  service_namespace  = aws_appautoscaling_target.scaling_target[each.key].service_namespace

  step_scaling_policy_configuration {
    adjustment_type         = "ChangeInCapacity"
    cooldown                = var.scale_down_cooldown_period
    metric_aggregation_type = "Maximum"

    step_adjustment {
      metric_interval_upper_bound = 0
      scaling_adjustment          = var.scale_down_adjustment
    }
  }
}

module "m2m_secrets" {
  source = "git@github.com:theorchard/terraform-secrets-manager.git//modules/auth0m2m?ref=1.6.1"

  environment        = var.environment
  service_name       = var.m2m_service_name
  application_family = var.application_family
}
