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
  }
}

provider "aws" {
  region  = var.aws_region
  alias   = "networking"
  profile = "networking"

  default_tags {
    tags = module.default_tags.tags
  }
}


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

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

  environment = var.environment
}

data "aws_caller_identity" "current" {}

data "aws_iam_policy" "s3_mezzanine_dir_readonly_policy" {
  name = "S3-${var.s3_video_bucket}-mezzanine-RO"
}

data "aws_iam_policy" "s3_mezzanine_assets_dir_readonly_policy" {
  name = "S3-${var.s3_mezz_bucket}-RO"
}

# RO access to encoding buckets
data "aws_iam_policy" "encoding_s3_policy" {
  for_each = {
    for policy in local.s3_policies_to_attach : policy.policy_name => policy
  }
  name = each.value.policy_name
}

# s3_store_delivery_bucket RW access
data "aws_iam_policy" "s3_store_delivery_bucket_policy" {
  name = "S3-${var.environment}-s3-store-delivery-RW-policy"
}

# S3 vector-audit RW access
data "aws_iam_policy" "s3_vector_audit_bucket_policy" {
  name = "S3-${var.environment}-vector-audit-RW"
}

# common sentry in qa for all delivery workers
module "delivery_worker_sentry_project" {
  source             = "git@github.com:theorchard/terraform-sentry.git//?ref=5.0.0"
  service_name       = var.service_name
  environment        = var.environment
  teams              = [var.environment]
  application_family = var.application_family
  platform           = "php"
}

data "aws_iam_policy_document" "kms_decryption_policy" {
  statement {
    actions = [
      "kms:Decrypt",
      "kms:DescribeKey",
    ]

    resources = [
      aws_kms_key.kms_key.arn,
    ]
  }
}

# Create KMS key and policies for certain encrypted configuration
resource "aws_kms_key" "kms_key" {
  description             = "${var.environment}-${var.service_name}"
  enable_key_rotation     = true
  deletion_window_in_days = 30
  tags                    = local.tags
}

resource "aws_kms_alias" "kms_alias" {
  name          = "alias/${var.environment}-${var.service_name}"
  target_key_id = aws_kms_key.kms_key.key_id
}

# Create KMS policy
resource "aws_iam_policy" "kms_policy" {
  name   = "KMS-${var.environment}-${var.service_name}-policy"
  policy = data.aws_iam_policy_document.kms_decryption_policy.json
  tags   = local.tags
}

# Create policy to List, Read and delete message from Delivery SQS queue
data "aws_iam_policy_document" "sqs_delivery_queue_policy_document" {
  statement {
    actions = [
      "sqs:GetQueueAttributes",
      "sqs:GetQueueUrl",
      "sqs:ListQueues",
      "sqs:SendMessageBatch",
      "sqs:SendMessage",
      "sqs:CreateQueue",
      "sqs:DeleteMessage",
      "sqs:ReceiveMessage",
    ]

    resources = [
      # To match arn:aws:sqs:us-east-1:437795906767:qa-delivery18_e0000005_d0000471
      "arn:aws:sqs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:${var.environment}-delivery17_e*",
      "arn:aws:sqs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:${var.environment}-delivery17_e*",
      "arn:aws:sqs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:${var.environment}-delivery18_e*",
      "arn:aws:sqs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:${var.environment}-delivery18_e*/*",
    ]
  }

  statement {
    actions = [
      "sqs:GetQueueAttributes",
      "sqs:ListQueues"
    ]

    resources = [
      "arn:aws:sqs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:*",
    ]
  }
}

resource "aws_iam_policy" "sqs_delivery_queue_policy" {
  name   = "sqs-${var.environment}-delivery-queue-RW-policy"
  policy = data.aws_iam_policy_document.sqs_delivery_queue_policy_document.json
}

# ows-request dynamo db policy
module "vector_delivery_service_owsrequest" {
  source = "git@github.com:theorchard/terraform-owsrequest.git//?ref=1.0.1"

  environment_name   = var.environment
  service_name       = var.service_name
  policy_description = "A policy to access dynamo owsrequest table"
}

# Create efs file system.
module "delivery_worker_efs" {
  source = "git@github.com:theorchard/terraform-efs.git//?ref=4.1.0"

  providers = {
    aws.dns = aws.networking
  }

  environment         = var.environment
  service_name        = var.service_name
  application_family  = var.application_family
  vpc_id              = module.vpc_info.vpc_id
  subnet_ids          = module.vpc_info.default_private_subnet_ids
  owner_gid           = "1010"
  owner_uid           = "1010"
  efs_throughput_mode = "elastic"
  backup_enabled      = false

  efs_ingress_additional_cidr_blocks = [
    "162.49.75.0/24", # Allow access from SME VPN
  ]
}

# Audio Delivery Worker
locals {
  # QA audio delivery uses the Fargate default 20 GiB disk, set explicitly here so the EFS threshold
  # derives from it (20 renders no ephemeral_storage block — behaviour-neutral). Threshold = disk − 8
  # GiB reserve (~4 GiB overhead + ~4 GiB scratch; smaller than video's 10 because audio packages are
  # tiny). Bigger packages stage on EFS. See prod video delivery for the measured breakdown.
  qa_audio_delivery_ephemeral_gib     = 20
  qa_audio_delivery_efs_threshold_gib = local.qa_audio_delivery_ephemeral_gib - 8
}

module "qa_vector_delivery_audio_ecs_service" {
  for_each = {
    for service in local.flattened_audio_service_list : "physical_location_${service.physical_location}-encoding_priority_${service.encoding_priority}" => service
  }

  source = "git@github.com:theorchard/terraform-fargate.git//?ref=6.1.1"

  providers = {
    aws.dns = aws.networking
  }

  environment                           = var.environment
  service_name                          = "${var.service_name}-audio-phys-loc-${each.value.physical_location}-p${each.value.encoding_priority}"
  non_ecr_image                         = "086679231553.dkr.ecr.${var.aws_region}.amazonaws.com/vector-worker:latest"
  vpc_id                                = module.vpc_info.vpc_id
  application_family                    = var.application_family
  secrets_manager_service_name          = var.service_name
  aws_region                            = var.aws_region
  commit_sha                            = "latest"
  task_type                             = "worker"
  health_check_command                  = "pgrep php"
  desired_task_count                    = each.value.min_task_count # Set during service creation here and controlled henceforth by autoscaling
  task_cpu                              = 256
  task_memory                           = 1024
  task_ephemeral_storage_size           = local.qa_audio_delivery_ephemeral_gib
  minimum_capacity                      = each.value.min_task_count
  maximum_capacity                      = each.value.max_task_count
  task_protection_policy_enabled        = true
  splitio_enabled                       = true
  ows_machine_to_machine_enabled        = false
  autoscaling_cpu_policy_enabled        = false
  autoscaling_memory_policy_enabled     = false
  external_autoscaling_policy_enabled   = true
  stopped_task_monitoring_enabled       = true
  fargate_capacity_provider_base        = 1
  fargate_capacity_provider_weight      = 1
  fargate_spot_capacity_provider_weight = 4
  force_new_deployment                  = true
  task_placement_failure_alert_enabled  = true

  iam_managed_policy_attachments = [
    aws_iam_policy.kms_policy.arn,
    aws_iam_policy.secrets_manager_delivery_spec_policy.arn,
    module.delivery_worker_efs.efs_iam_policy_arn_output,
  ]

  docker_volumes = [
    {
      name            = "${var.environment}-${var.service_name}"
      file_system_id  = module.delivery_worker_efs.efs_file_system_id_output
      access_point_id = module.delivery_worker_efs.efs_access_point_id_output
    }
  ]

  docker_volume_mount_points = [
    {
      source_volume  = "${var.environment}-${var.service_name}"
      container_path = var.efs_mount_path
    }
  ]

  fargate_service_subnets = module.vpc_info.default_private_subnet_ids

  environment_variables = [
    {
      Environment = var.environment
    },
    {
      PHP_ENTRYPOINT = "deliver_tracks.php"
    },
    {
      ALLOWED_ENCODER_IDS = var.audio_encoder_id
    },
    {
      WGET_IP = "webservices.qaorch.com"
    },
    {
      API_GATEWAY = "ul7vwqbzwa-vpce-04f8c4be29fb2bd59.execute-api.us-east-1.amazonaws.com"
    },
    {
      ENCODING_PRIORITIES = each.value.encoding_priority
    },
    {
      LOG_LEVEL = "7"
    },
    {
      PHYSICAL_LOCATION_ID = each.value.physical_location
    },
    {
      SCRIPT_COUNT = "10"
    },
    {
      transporter_log_location = "itmsextremelogs"
    },
    {
      PRODUCT_STORE_MAPPING_URL = "https://qa-ows-product-store-mapping.theorchard.io"
    },
    {
      WORKER_TIMEOUT = "12h"
    },
    {
      USE_DOGSTATSD = "true"
    },
    {
      SENTRY_DSN = module.delivery_worker_sentry_project.sentry_key_dsn_public_output
    },
    {
      SERVICE_NAME = var.service_name
    },
    {
      USE_EFS_FOR_PACKAGES_LARGER_THAN_GIB = tostring(local.qa_audio_delivery_efs_threshold_gib)
    },
    {
      EFS_PATH = var.efs_mount_path
    },
    {
      DD_DB_HOST = "qadddb.qaorch.com"
    },
    {
      DD_DB_RW_USERNAME = "qa-dd_user_rw"
    },
    {
      DD_DB_RO_USERNAME = "qa-dd_user_ro"
    },
    {
      DD_DB_EO_USERNAME = "qa-dd_user"
    },
    {
      AR_DB_HOST = "qa-art-relations.cluster-ro-cb22xqmk0y0q.us-east-1.rds.amazonaws.com"
    },
    {
      AR_DB_USERNAME = "qa-theorchard_dd"
    },
    {
      S3_XML_BACKUP_BUCKET = "qa-vector-audit"
    },
    {
      S3_XML_BACKUP_PATH = "/metadata"
    },
    {
      CACHE_HOST = "qa-vector-redis.theorchard.io"
    },
    {
      ENCODING_QUEUE_NAME_PATTERN = "qa-encoding{encoder-id}_e{priority(7)}_d{dms-priority(7)}"
    },
    {
      DELIVERY_QUEUE_NAME_PATTERN = "qa-delivery{encoder-id}_e{priority(7)}_d{dms-priority(7)}"
    },
    {
      APP_LOG_LEVEL = var.app_log_level
    }
  ]

  secrets = [
    {
      AR_DB_PASSWORD = "${var.environment}/${var.service_name}/AR_DB_PASSWORD"
    },
    {
      DD_DB_RO_PASSWORD = "${var.environment}/${var.service_name}/DD_DB_RO_PASSWORD"
    },
    {
      DD_DB_RW_PASSWORD = "${var.environment}/${var.service_name}/DD_DB_RW_PASSWORD"
    },
    {
      DD_DB_EO_PASSWORD = "${var.environment}/${var.service_name}/DD_DB_EO_PASSWORD"
    },
    {
      AWS_KEY_ID = "${var.environment}/${var.service_name}/AWS_KEY_ID"
    },
    {
      AWS_SECRET_KEY = "${var.environment}/${var.service_name}/AWS_SECRET_KEY"
    },
  ]
}

# This rule allows audio delivery fargate tasks to access the EFS mount
resource "aws_security_group_rule" "qa_vector_delivery_audio_allow_efs_sg_inbound" {
  for_each = {
    for service in local.flattened_audio_service_list : "physical_location_${service.physical_location}-encoding_priority_${service.encoding_priority}" => service
  }

  from_port                = 2049
  protocol                 = "tcp"
  security_group_id        = module.delivery_worker_efs.efs_security_group_id_output
  source_security_group_id = module.qa_vector_delivery_audio_ecs_service[each.key].fargate_security_group_id
  to_port                  = 2049
  type                     = "ingress"
}

resource "aws_iam_role_policy_attachment" "vector_delivery_audio_secrets_manager_storage_credential_policy_attachment" {
  for_each = {
    for service in local.flattened_audio_service_list : "physical_location_${service.physical_location}-encoding_priority_${service.encoding_priority}" => service
  }
  role       = module.qa_vector_delivery_audio_ecs_service[each.key].fargate_task_iam_execution_role_name
  policy_arn = aws_iam_policy.secrets_manager_storage_credential_policy[each.value.physical_location].arn
}

locals {
  # QA video delivery runs on the Fargate default 20 GiB ephemeral disk, set explicitly below so
  # the EFS threshold can be derived from it (the module renders no ephemeral_storage block at 20,
  # so it is behaviour-neutral). Threshold = disk minus a fixed ~10 GiB reserved for overhead that
  # does not scale with the disk (Fargate platform + idle baseline incl. decompressed images +
  # ~0.15 GiB measured delivery scratch + safety). See prod video delivery for the breakdown.
  qa_video_delivery_ephemeral_gib     = 20
  qa_video_delivery_efs_threshold_gib = local.qa_video_delivery_ephemeral_gib - 10
}

# Video Delivery Worker
module "qa_vector_delivery_video_ecs_service" {
  for_each = {
    for service in local.flattened_video_service_list : "physical_location_${service.physical_location}-encoding_priority_${service.encoding_priority}" => service
  }

  source = "git@github.com:theorchard/terraform-fargate.git//?ref=6.1.1"

  providers = {
    aws.dns = aws.networking
  }

  environment                           = var.environment
  service_name                          = "${var.service_name}-video-phys-loc-${each.value.physical_location}-p${each.value.encoding_priority}"
  non_ecr_image                         = "086679231553.dkr.ecr.${var.aws_region}.amazonaws.com/${var.service_name}:latest"
  vpc_id                                = module.vpc_info.vpc_id
  application_family                    = var.application_family
  secrets_manager_service_name          = var.service_name
  aws_region                            = var.aws_region
  commit_sha                            = "latest"
  task_type                             = "worker"
  health_check_command                  = "pgrep php"
  desired_task_count                    = each.value.min_task_count # Set during service creation here and controlled henceforth by autoscaling
  task_cpu                              = 256
  task_memory                           = 1024
  task_ephemeral_storage_size           = local.qa_video_delivery_ephemeral_gib
  minimum_capacity                      = each.value.min_task_count
  maximum_capacity                      = each.value.max_task_count
  task_protection_policy_enabled        = true
  splitio_enabled                       = true
  ows_machine_to_machine_enabled        = false
  autoscaling_cpu_policy_enabled        = false
  autoscaling_memory_policy_enabled     = false
  external_autoscaling_policy_enabled   = true
  stopped_task_monitoring_enabled       = true
  fargate_spot_capacity_provider_weight = 100
  task_placement_failure_alert_enabled  = true

  # IAM policies used by the task role to pull configs from s3
  iam_managed_policy_attachments = [
    aws_iam_policy.kms_policy.arn,
    aws_iam_policy.secrets_manager_delivery_spec_policy.arn,
    module.delivery_worker_efs.efs_iam_policy_arn_output,
  ]

  docker_volumes = [
    {
      name            = "${var.environment}-${var.service_name}"
      file_system_id  = module.delivery_worker_efs.efs_file_system_id_output
      access_point_id = module.delivery_worker_efs.efs_access_point_id_output
    }
  ]

  docker_volume_mount_points = [
    {
      source_volume  = "${var.environment}-${var.service_name}"
      container_path = var.efs_mount_path
    }
  ]

  fargate_service_subnets = module.vpc_info.default_private_subnet_ids

  environment_variables = [
    {
      Environment = var.environment
    },
    {
      PHP_ENTRYPOINT = "deliver_tracks.php"
    },
    {
      ALLOWED_ENCODER_IDS = var.video_encoder_id
    },
    {
      WGET_IP = "webservices.qaorch.com"
    },
    {
      API_GATEWAY = "ul7vwqbzwa-vpce-04f8c4be29fb2bd59.execute-api.us-east-1.amazonaws.com"
    },
    {
      ENCODING_PRIORITIES = each.value.encoding_priority
    },
    {
      LOG_LEVEL = "7"
    },
    {
      PHYSICAL_LOCATION_ID = each.value.physical_location
    },
    {
      SCRIPT_COUNT = "5"
    },
    {
      transporter_log_location = "itmsextremelogs"
    },
    {
      PRODUCT_STORE_MAPPING_URL = "https://qa-ows-product-store-mapping.theorchard.io"
    },
    {
      WORKER_TIMEOUT = "24h"
    },
    {
      USE_DOGSTATSD = "true"
    },
    {
      SENTRY_DSN = module.delivery_worker_sentry_project.sentry_key_dsn_public_output
    },
    {
      SERVICE_NAME = var.service_name
    },
    {
      USE_EFS_FOR_PACKAGES_LARGER_THAN_GIB = tostring(local.qa_video_delivery_efs_threshold_gib)
    },
    {
      EFS_PATH = var.efs_mount_path
    },
    {
      DD_DB_HOST = "qadddb.qaorch.com"
    },
    {
      DD_DB_RW_USERNAME = "qa-dd_user_rw"
    },
    {
      DD_DB_RO_USERNAME = "qa-dd_user_ro"
    },
    {
      DD_DB_EO_USERNAME = "qa-dd_user"
    },
    {
      AR_DB_HOST = "qa-art-relations.cluster-ro-cb22xqmk0y0q.us-east-1.rds.amazonaws.com"
    },
    {
      AR_DB_USERNAME = "qa-theorchard_dd"
    },
    {
      S3_XML_BACKUP_BUCKET = "qa-vector-audit"
    },
    {
      S3_XML_BACKUP_PATH = "/metadata"
    },
    {
      CACHE_HOST = "qa-vector-redis.theorchard.io"
    },
    {
      ENCODING_QUEUE_NAME_PATTERN = "qa-encoding{encoder-id}_e{priority(7)}_d{dms-priority(7)}"
    },
    {
      DELIVERY_QUEUE_NAME_PATTERN = "qa-delivery{encoder-id}_e{priority(7)}_d{dms-priority(7)}"
    },
    {
      APP_LOG_LEVEL = var.app_log_level
    }
  ]

  secrets = [
    {
      AR_DB_PASSWORD = "${var.environment}/${var.service_name}/AR_DB_PASSWORD"
    },
    {
      DD_DB_RO_PASSWORD = "${var.environment}/${var.service_name}/DD_DB_RO_PASSWORD"
    },
    {
      DD_DB_RW_PASSWORD = "${var.environment}/${var.service_name}/DD_DB_RW_PASSWORD"
    },
    {
      DD_DB_EO_PASSWORD = "${var.environment}/${var.service_name}/DD_DB_EO_PASSWORD"
    },
    {
      AWS_KEY_ID = "${var.environment}/${var.service_name}/AWS_KEY_ID"
    },
    {
      AWS_SECRET_KEY = "${var.environment}/${var.service_name}/AWS_SECRET_KEY"
    },
  ]
}

# Every service in a given physical location should have the S3 policy for that location attached to it
resource "aws_iam_role_policy_attachment" "vector_delivery_video_secrets_manager_storage_credential_policy_attachment" {
  for_each = {
    for service in local.flattened_video_service_list : "physical_location_${service.physical_location}-encoding_priority_${service.encoding_priority}" => service
  }
  role       = module.qa_vector_delivery_video_ecs_service[each.key].fargate_task_iam_execution_role_name
  policy_arn = aws_iam_policy.secrets_manager_storage_credential_policy[each.value.physical_location].arn
}

# This rule allows video delivery fargate tasks to access the EFS mount
resource "aws_security_group_rule" "qa_vector_delivery_video_allow_efs_sg_inbound" {
  for_each = {
    for service in local.flattened_video_service_list : "physical_location_${service.physical_location}-encoding_priority_${service.encoding_priority}" => service
  }

  from_port                = 2049
  protocol                 = "tcp"
  security_group_id        = module.delivery_worker_efs.efs_security_group_id_output
  source_security_group_id = module.qa_vector_delivery_video_ecs_service[each.key].fargate_security_group_id
  to_port                  = 2049
  type                     = "ingress"
}

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

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