# General settings
variable "aws_region" {
  default = "us-east-1"
}

variable "environment" {
  description = "Name of environment, e.g. dev, sandbox, qa, prod"
  default     = "dev"
}

variable "service_name" {
  description = "Name of service"
  default     = "ows-service"
}

variable "application_family" {
  type        = string
  description = "Application family to which this service belongs"
}

variable "propagate_tags" {
  type        = string
  default     = true
  description = "Whether or not to propagate tags from service to tasks"
}

variable "additional_tags" {
  type        = map(string)
  description = "Optional map of additional tags to set on resources. These will be combined with programmatically set required tags."
  default     = {}
}

variable "additional_docker_labels" {
  type        = map(string)
  description = "Optional map of additional dockerLabels"
  default     = {}
}

variable "container_insights_enabled" {
  description = "Whether or not to enable Container Insights for additional metrics"
  default     = true
}

variable "secrets_manager_service_name" {
  description = "Override secrets manager service name in iam policy"
  default     = ""
}

variable "ows_machine_to_machine_enabled" {
  description = "Whether or not to attach ows machine-to-machine secretsmanager IAM policy"
  default     = true
}

variable "splitio_enabled" {
  description = "Whether or not to attach Split secretsmanager IAM policy"
  default     = true
}

variable "datadog_enabled" {
  description = "Whether or not to attach datadog secretsmanager IAM policy"
  default     = true
}

variable "datadog_task_cpu" {
  description = "Datadog task CPU"
  default     = 64
}

variable "datadog_task_memory" {
  description = "Datadog task memory"
  default     = 256
}

variable "datadog_custom_image" {
  description = "Custom datadog image. Specifying this value will use the provided image for the Datadog sidecar container"
  default     = ""
}

variable "fluentbit_task_cpu" {
  description = "fluentbit task CPU"
  default     = 64
}

variable "fluentbit_task_memory" {
  description = "fluentbit task memory"
  default     = 64
}

variable "fluentbit_custom_image" {
  description = "Custom fluent-bit image. Specifying this value will use the provided image for the FluentBit sidecar container"
  default     = ""
}

variable "log_router_log_level" {
  description = "Log level for log router. Values are error, warn, info, debug, trace."
  default     = "info"
}

variable "availability_zone_rebalancing" {
  description = "Whether or not to enable availability zone rebalancing"
  default     = "ENABLED"
  validation {
    condition     = contains(["DISABLED", "ENABLED"], var.availability_zone_rebalancing)
    error_message = "availability_zone_rebalancing should be set to either ENABLED or DISABLED."
  }
}

# Task/Container settings
variable "use_custom_task_definition_file" {
  description = "Whether or not to use a custom task definition file"
  default     = false
}

variable "task_definition_file_location" {
  description = "Location of custom task definition file. Only set if var.use_custom_task_definition_file is set to true"
  default     = ""
}

variable "commit_sha" {
  description = "SHA of commit to use in container definition"
  default     = "latest"
}

variable "container_port" {
  description = "Container port to associate with service load balancer"
  default     = 8080
}

variable "container_protocol" {
  description = "Protocol exposed by container tasks"
  default     = "HTTP"
}

variable "container_protocol_version" {
  description = "Protocol version used when protocol is HTTP or HTTPS. Valid values are GRPC, HTTP1, and HTTP2. If unset, HTTP1 is the default."
  default     = ""
}

variable "deployment_minimum_healthy_percent" {
  description = "Minimum percent of tasks that should remain healthy during deployment"
  default     = "50"
}

variable "deployment_maximum_percent" {
  description = "Maximum percent of tasks that should be running during deployment"
  default     = "200"
}

variable "deployment_circuit_breaker_enabled" {
  description = "Enable the ECS deployment circuit breaker. Marks a deployment FAILED when consecutive task launch/health attempts breach the ECS-managed threshold."
  type        = bool
  default     = false
}

variable "deployment_circuit_breaker_rollback_enabled" {
  description = "When the circuit breaker trips, automatically roll the service back to the last completed deployment. Ignored unless deployment_circuit_breaker_enabled is true."
  type        = bool
  default     = false
}

variable "desired_task_count" {
  description = "Number of tasks to run for a given service"
  default     = 1
}

variable "task_cpu" {
  description = "CPU requirements for task definition"
  default     = 256
}

variable "task_memory" {
  description = "Memory requirements for task definition"
  default     = 512
}

variable "task_ephemeral_storage_size" {
  description = "Ephemeral storage size from 20 to 200 GiB."
  default     = 20
}

variable "task_type" {
  description = "Type of task. Valid options are web_service and worker."
  default     = "web_service"
}

# Load balancer settings
variable "load_balancer_enable_deletion_protection" {
  description = "Whether or not to enable deletion protection via API. Stops Terraform from deleting this resource."
  default     = false
}

variable "load_balancer_is_internal" {
  description = "Boolean to indicate if load balancer is internal"
  default     = true
}

variable "load_balancer_access_logs_s3_bucket_name" {
  description = "S3 bucket for storing load balancer access logs"
  default     = "aws-logs-103233932089-us-east-1"
}

variable "load_balancer_access_logs_prefix" {
  description = "The S3 bucket prefix."
  default     = ""
}

variable "load_balancer_idle_timeout" {
  description = "Load balancer idle timeout in seconds"
  default     = "60"
}

variable "load_balancer_subnets" {
  description = "Subnets (in multiple AZs) for load balancer"
  type        = list(string)

  default = [
    "subnet-44c19a21",
    "subnet-b649dfef",
  ]
}

# HTTP listener settings
variable "http_listener_enabled" {
  description = "Whether or not HTTP listener will be created"
  default     = false
}

variable "http_listener_port" {
  description = "Port for HTTP listener."
  default     = "80"
}

variable "http_listener_public_allow_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTP for public services"
  type        = list(string)
  default     = []
}

variable "dev_http_listener_allow_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTP for dev environments"
  type        = list(string)

  default = [
    "169.254.169.254/32",
  ]
}

variable "qa_http_listener_allow_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTP for QA environments"
  type        = list(string)

  default = [
    "169.254.169.254/32",
  ]
}

variable "prod_http_listener_allow_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTP for prod environments"
  type        = list(string)

  default = [
    "169.254.169.254/32",
  ]
}

# HTTPS listener settings
variable "https_listener_enabled" {
  description = "Whether or not HTTPS listener will be created"
  default     = true
}

variable "https_listener_port" {
  description = "Port for HTTPS listener."
  default     = "443"
}

variable "https_listener_public_allow_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTPS for public services"
  type        = list(string)
  default     = []
}

variable "dev_https_listener_allow_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTPS for dev environments"
  type        = list(string)
  default     = []
}

variable "qa_https_listener_allow_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTPS for QA environments"
  type        = list(string)
  default     = []
}

variable "prod_https_listener_allow_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTPS for prod environments"
  type        = list(string)
  default     = []
}

variable "https_listener_allow_prefix_list_names" {
  description = "Additional prefix list names from which to allow HTTPS"
  type        = list(string)
  default     = []
}

variable "http_listener_allow_prefix_list_names" {
  description = "Additional prefix list names from which to allow HTTP"
  type        = list(string)
  default     = []
}

variable "https_listener_allow_security_group_ids" {
  description = "List of security group IDs from which to allow HTTPS."
  type        = list(string)
  default     = []
}

variable "https_listener_ssl_policy" {
  description = "HTTPS listener SSL policy"
  default     = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}

variable "https_listener_domain_for_certificate" {
  description = "Name of domain for which to use the SSL certificate in ACM for use by load balancer"
  default     = ""
}

variable "https_listener_certificate_id" {
  description = "ID of SSL cerficate in ACM for use by load balancer"
  default     = ""
}

# Health check settings
variable "health_check_retries" {
  description = "Container health check number of retries before considering task unhealthy"
  default     = "3"
}

variable "health_check_grace_period_seconds" {
  description = "Grace period to allow failing healthchecks before considering task failed"
  default     = "60"
}

variable "container_start_period_seconds" {
  description = "Start period for container health checks"
  default     = "60"
}

variable "health_check_healthy_threshold" {
  description = "Number of consecutive positive health checks before a target is considered healthy"
  default     = "3"
}

variable "health_check_interval" {
  description = "Intervals between health checks of target"
  default     = "10"
}

variable "health_check_matcher" {
  description = "Status codes used for successful health check"
  type        = string
  default     = "200"
}

variable "health_check_mode" {
  description = "The way healthcheck command will be executed. Valid values CMD or CMD-SHELL"
  default     = "CMD-SHELL"
  validation {
    condition     = contains(["CMD", "CMD-SHELL"], var.health_check_mode)
    error_message = "Health check mode should be set to either CMD or CMD-SHELL."
  }
}

variable "health_check_path" {
  description = "Path used for health check"
  default     = "/hello/"
}

variable "health_check_timeout" {
  description = "Seconds for health check to wait before failing check"
  default     = "5"
}

variable "health_check_unhealthy_threshold" {
  description = "Number of consecutive positive health checks before a target is considered unhealthy."
  default     = "3"
}

variable "health_check_command" {
  description = "custom comamnd for health checks in CMD-SHELL mode"
  default     = "/bin/bash /var/app/conf/healthcheck.sh"
}

variable "web_service_health_check_command" {
  description = "custom command for web service tasks health checks in CMD-SHELL mode"
  default     = ""
}

variable "health_check_command_list" {
  description = "Command with arguments as a list for health check in CMD mode"
  default     = []
}

# ulimit settings
variable "ulimit_nofile_soft_limit" {
  description = "Soft limit for open files"
  default     = 4096
}

variable "ulimit_nofile_hard_limit" {
  description = "Hard limit for open files"
  default     = 65535
}

# Network settings
variable "fargate_service_subnets" {
  description = "Subnets in which to run service tasks"
  type        = list(string)

  default = [
    "subnet-44c19a21",
    "subnet-b649dfef",
  ]
}

variable "vpc_id" {
  description = "VPC in which to run the task"
  default     = "vpc-34dbfd51"
}

variable "route53_record_ttl" {
  description = "TTL associated with Route53 CNAME record"
  default     = "60"
}

variable "override_route53_zone_id" {
  description = "AWS Route 53 zone id"
  default     = null
}

variable "route53_record_creation_enabled" {
  description = "Whether or not to create Route 53 DNS records"
  default     = true
}

# Target group settings
variable "target_deregistration_delay" {
  description = "Deregistration delay for target group tasks"
  default     = "60"
}

variable "target_group_cookie_duration" {
  description = "Cookie duration in seconds for sticky sessions"
  default     = "86400"
}

variable "target_group_stickiness_enabled" {
  description = "Whether or not sticky sessions are enabled"
  default     = false
}

# IAM settings
variable "iam_managed_policy_attachments" {
  description = "List of ARNs of existing IAM policies to attach to role"
  type        = list(string)
  default     = []
}

variable "iam_policy_file_enabled" {
  description = "Does this function require additional IAM policies? If so set this to true and add a file in ./policies/var.service_name.json"
  default     = false
}

variable "execution_role_iam_managed_policy_attachments" {
  description = "List of ARNs of existing IAM policies to attach to Execution Role"
  type        = list(string)
  default     = []
}

# Cloudwatch event variables
variable "cloudwatch_event_enabled" {
  description = "Whether or not to create a Cloudwatch event to run fargate task on schedule"
  default     = false
}

variable "cloudwatch_event_schedule" {
  description = "Schedule for Cloudwatch event. Specify a cron() or rate() expression"
  default     = "cron(0 0 * ? *)"
}

variable "cloudwatch_event_task_count_per_event" {
  description = "How many tasks to run per Cloudwatch event trigger"
  default     = "1"
}

variable "assign_public_ip" {
  description = "Whether or not to assign public IP when running task via Cloudwatch event"
  default     = false
}

# Autoscaling settings
variable "autoscaling_cpu_policy_enabled" {
  description = "Whether or not CPU autoscaling policy is enabled"
  default     = true
}

variable "autoscaling_memory_policy_enabled" {
  description = "Whether or not memory autoscaling policy is enabled"
  default     = false
}

variable "autoscaling_load_balancer_policy_enabled" {
  description = "Whether or not application load balancer autoscaling policy is enabled"
  default     = false
}

variable "autoscaling_active_connections_policy_enabled" {
  description = "Whether or not active connection count autoscaling policy is enabled"
  default     = false
}

variable "external_autoscaling_policy_enabled" {
  description = "Whether or not an external autoscaling policy is enabled. Set to true to create an autoscaling target with no internal policy."
  default     = false
}

variable "minimum_capacity" {
  description = "Minimum number of tasks for service"
  default     = 1
}

variable "maximum_capacity" {
  description = "Maximum number of tasks for service"
  default     = 2
}

variable "scale_in_cooldown_period" {
  description = "Cooldown period, in seconds, between scale in events"
  default     = "300"
}

variable "scale_out_cooldown_period" {
  description = "Cooldown period, in seconds, between scale out events"
  default     = "30"
}

variable "scaling_cpu_target_value" {
  description = "The desired CPU utilization value"
  default     = "40"
}

variable "scaling_memory_target_value" {
  description = "The desired memory utilization value"
  default     = "50"
}

variable "scaling_load_balancer_target_value" {
  description = "The desired number of requests per target in an application load balancer target group"
  default     = "300"
}

variable "scaling_active_connection_count_scale_out_threshold" {
  description = "The threshold of active connections per target above which step scale out policies will take effect"
  default     = "50"
}

variable "scaling_active_connection_count_scale_out_number_of_evaluation_periods" {
  type        = number
  description = "The number of evaluation periods for active connections scale out step scaling policy"
  default     = 3
}

variable "scaling_active_connection_count_scale_in_threshold" {
  description = "The threshold of active connections per target below which step scale in policies will take effect"
  default     = "25"
}

variable "scaling_active_connection_count_scale_in_number_of_evaluation_periods" {
  type        = number
  description = "The number of evaluation periods for active connections scale in step scaling policy"
  default     = 3
}

variable "scaling_active_connection_count_evaluation_period_seconds" {
  type        = number
  description = "The number of seconds over which to apply active connection count evaluation"
  default     = 60
}

variable "active_connections_autoscaling_scale_out_adjustment" {
  type        = number
  description = "Number tasks to add in a single scaling event"
  default     = 2
}

variable "active_connections_autoscaling_scale_in_adjustment" {
  type        = number
  description = "Number tasks to remove in a single scaling event"
  default     = -1
}

variable "max_session_duration" {
  description = "The maximum session duration (in seconds) that you want to set for the specified role. If you do not specify a value for this setting, the default maximum of one hour is applied. This setting can have a value from 1 hour to 12 hours."
  default     = "3600"
}

# Volume variables
variable "docker_volumes" {
  description = "A list of maps describing volumes to be used by tasks."
  type = list(object({
    name             = string
    type             = optional(string, "EFS")
    file_system_id   = optional(string)
    access_point_id  = optional(string)
    file_system_type = optional(string)
    iops             = optional(number)
    kms_key_id       = optional(string)
    size_in_gb       = optional(number)
    snapshot_id      = optional(string)
    throughput       = optional(number)
    volume_type      = optional(string)
  }))
  default = []

  validation {
    condition     = alltrue([for volume in var.docker_volumes : contains(["EBS", "EFS", "BIND_MOUNT"], volume.type)])
    error_message = "Docker volume types must be one of EBS, EFS or BIND_MOUNT"
  }

  validation {
    condition     = alltrue([for volume in var.docker_volumes : (volume.file_system_id != null && volume.access_point_id != null) || volume.type != "EFS"])
    error_message = "If Docker volume type is EFS then file_system_id and access_point_id must be specified"
  }
}

variable "docker_volume_mount_points" {
  description = "A list of mount points to include in the main container definition."
  type = list(object({
    source_volume  = string
    container_path = string
    read_only      = optional(bool, false)
  }))
  default = []
}

# Environment variables
# This must be a list of maps with at least one element.
variable "environment_variables" {
  description = "List of environment variables to pass into container"
  type        = list(map(string))

  default = [
    {
      Environment = "dev"
    },
    {
      LOGGER_DSN = "url"
    },
  ]
}

variable "datadog_agent_environment_variables" {
  description = "List of environment variables to pass into datadog-agent container"
  type        = list(map(string))

  default = []
}

variable "auth_issuers" {
  type        = map(string)
  description = "A comma-separated list of issuers for consumption by Auth0 libraries. This is mapped to the AUTH_ISSUERS environment variable inside the container"
  default = {
    dev    = "https://qalogin.theorchard.com/, https://qa-orchard.auth0.com/"
    qa     = "https://qalogin.theorchard.com/, https://qa-orchard.auth0.com/"
    uat    = "https://qalogin.theorchard.com/, https://qa-orchard.auth0.com/"
    prod   = "https://login.distroauth.com/, https://workstation.auth0.com/"
    backup = "https://login.distroauth.com/, https://workstation.auth0.com/"
    shared = "https://login.distroauth.com/, https://workstation.auth0.com/"
  }
}

variable "secrets" {
  description = "List of environment variables keys and the secrets-manager location of their values"
  type        = list(map(string))

  default = []
}

variable "non_ecr_image" {
  default = ""
}

variable "custom_security_group_ids" {
  default     = []
  type        = list(string)
  description = "An optional array of additional security group ids to attach directly to a fargate task"
}

variable "additional_lb_target_group_arns" {
  type        = list(string)
  default     = []
  description = "An optional array of additional custom target group arns to attach to a 'worker' ECS task default service port"
}

variable "additional_lb_target_groups" {
  description = "Additional target groups with ability to specify non-default ports and containers"
  type = list(object({
    container_name   = string
    target_group_arn = string
    container_port   = number
  }))
  default = []
}

variable "blocking_waf_enabled" {
  description = "Use the blocking WAF or the alert/count only one"
  default     = true
}

variable "custom_waf_arn" {
  type        = string
  description = "Set this to use a custom WAF rather than the default shared WAF."
  default     = ""
}

# SWF monitor settings
variable "swf_worker_enabled" {
  type        = bool
  description = "Whether or not the application is a swf worker"
  default     = false
}

variable "swf_monitor_task_cpu" {
  description = "SWF monitor task CPU"
  default     = 128
}

variable "swf_monitor_task_memory" {
  description = "SWF monitor task memory"
  default     = 256
}

variable "swf_monitor_domain" {
  description = "Name of SWF domain for monitor"
  default     = "dev_swf_feed_ingestion"
}

variable "swf_monitor_workflow_name" {
  description = "Name of SWF workflow name for monitor"
  default     = ""
}

# Swap configuration for external tasks
variable "max_swap" {
  type        = number
  description = "The amount of swap space available to the primary container in MiB. This only applies to external tasks and swap must be configured on the host. If set to zero (default), swap is disabled."
  default     = 0
}

variable "swappiness" {
  type        = number
  description = "The swappiness setting for the primary container. This only applies to external tasks, and max_swap must be set to a non-zero value."
  default     = 60

  validation {
    condition     = var.swappiness >= 0 && var.swappiness <= 100
    error_message = "Swappiness must be a value between 0 and 100."
  }
}

# PrismaCloud Defender
variable "defender" {
  description = "Prisma Cloud defender configuration"
  type = object({
    enabled                       = bool
    task_cpu                      = optional(number, 64)
    task_memory                   = optional(number, 256)
    filesystem_monitoring_enabled = optional(bool, false)
    ws_address                    = optional(string, "wss://us-east1.cloud.twistlock.com:443")
    custom_image                  = optional(string, "")
  })
  default = {
    enabled                       = false
    task_cpu                      = 64
    task_memory                   = 256
    filesystem_monitoring_enabled = false
    ws_address                    = "wss://us-east1.cloud.twistlock.com:443"
    custom_image                  = ""
  }
}

variable "additional_http_ports" {
  description = "List of http port mappings"
  type = list(object({
    host_port          = number
    container_port     = number
    http_listener_port = number
    protocol           = string
  }))
  default = []
}

variable "additional_https_ports" {
  description = "List of https port mappings"
  type = list(object({
    host_port           = number
    container_port      = number
    https_listener_port = number
    protocol            = string
  }))
  default = []
}

variable "additional_ports" {
  description = "List of generic port mappings"
  type = list(object({
    host_port      = number
    container_port = number
    protocol       = string
  }))
  default = []
}

variable "log_configuration_options_override" {
  description = "A map of log configuration options to override the default log configuration for the Fluent Bit sidecar container"
  type        = map(string)
  default     = {}
}

variable "firelens_configuration_options_override" {
  description = "A map of configuration options to override the default Firelens configuration for the Fluent Bit sidecar container"
  type        = map(string)
  default     = {}
}

locals {
  container_insights_setting                                 = var.container_insights_enabled ? "enabled" : "disabled"
  shared_services_account_id                                 = "086679231553"
  datadog_image                                              = var.datadog_custom_image != "" ? var.datadog_custom_image : "${local.shared_services_account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/orchard-datadog-agent:latest"
  fluentbit_image                                            = var.fluentbit_custom_image != "" ? var.fluentbit_custom_image : "${local.shared_services_account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/orchard-fluent-bit:latest"
  defender_image                                             = var.defender.custom_image != "" ? var.defender.custom_image : "${local.shared_services_account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/prisma-cloud-defender:latest"
  datadog_secrets_manager_policy_arn                         = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/SecretsManager-${var.environment}-datadog-policy"
  ows_machine_to_machine_manager_policy_arn                  = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/SecretsManager-${var.environment}-ows-machine-to-machine-policy"
  python_orchard_features_splitio_secrets_manager_policy_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/secretsmanager-${var.environment}-python-orchard-features-SPLITIO_API_KEY-ro"
  split_secrets_manager_policy_arn                           = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/SecretsManager-${var.environment}-split-policy"
  swf_workflow_monitor_policy_arn                            = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/swf-workflow-monitor-policy"

  # If var.docker_volumes is specified, use the EFS-compatible task definition template
  task_type                                  = var.swf_worker_enabled ? "swf_worker" : var.task_type
  default_container_definition_template_file = "${path.module}/${local.task_type}_task_definition_template_file.json"
  default_web_service_health_check_command   = "curl -f http://localhost:${var.container_port}${var.health_check_path} || exit 1"

  sidecar_task_cpu    = var.fluentbit_task_cpu + (var.swf_worker_enabled ? var.swf_monitor_task_cpu : 0) + (var.defender.enabled ? var.defender.task_cpu : 0) + (var.task_type != "external_worker" ? var.datadog_task_cpu : 0)
  sidecar_task_memory = var.fluentbit_task_memory + (var.swf_worker_enabled ? var.swf_monitor_task_memory : 0) + (var.defender.enabled ? var.defender.task_memory : 0) + (var.task_type != "external_worker" ? var.datadog_task_memory : 0)

  application_task_cpu    = var.task_cpu - local.sidecar_task_cpu
  application_task_memory = var.task_memory - local.sidecar_task_memory

  additional_environment_variables_by_task_type = {
    external_worker = [
      {
        # On external workers, send traces to the Datadog agent running on the host.
        # We can assume that the host is always accessible on the IP 172.17.0.1, as this is the gateway for the default bridge network
        # and we always run external workers in "bridge" networking mode.
        DD_AGENT_HOST = "172.17.0.1"
      }
    ]
  }
  additional_environment_variables_for_task_type = lookup(local.additional_environment_variables_by_task_type, var.task_type, [])

  # Add additional environment variables, such as Auth0 and DataDog-specific.
  environment_variables = concat([
    {
      DD_APPSEC_SCA_ENABLED = "true"
    },
    {
      DD_ENV = var.environment
    },
    {
      DD_SERVICE = var.service_name
    },
    {
      AUTH_ISSUERS = lookup(var.auth_issuers, var.environment, "https://qalogin.theorchard.com/, https://qa-orchard.auth0.com/")
    },
  ], var.environment_variables, local.additional_environment_variables_for_task_type)

  environment_variables_combined = join(
    ",",
    [
      for idx, _ in local.environment_variables : templatefile(
        "${path.module}/environment_variables.json.tpl",
        {
          name  = element(keys(local.environment_variables[idx]), 0)
          value = element(values(local.environment_variables[idx]), 0)
        }
      )
    ]
  )


  datadog_agent_environment_variables = concat([
    {
      DD_SITE = "datadoghq.com"
    },
    {
      ECS_FARGATE = "true"
    },
    {
      DD_APM_ENABLED = "true"
    },
    {
      DD_APM_IGNORE_RESOURCES = "^GET ${var.health_check_path}$"
    },
    {
      DD_LOGS_ENABLED = "true"
    },
    {
      DD_OTLP_CONFIG_LOGS_ENABLED = "true"
    },
    {
      DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_ENDPOINT = "0.0.0.0:4317"
    },
    {
      DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT = "0.0.0.0:4318"
    },
    {
      DD_ECS_TASK_COLLECTION_ENABLED = "true"
    },
  ], var.datadog_agent_environment_variables)

  datadog_agent_environment_variables_combined = join(
    ",",
    [
      for idx, _ in local.datadog_agent_environment_variables : templatefile(
        "${path.module}/environment_variables.json.tpl",
        {
          name  = element(keys(local.datadog_agent_environment_variables[idx]), 0)
          value = element(values(local.datadog_agent_environment_variables[idx]), 0)
        }
      )
    ]
  )

  secrets_combined = join(
    ",",
    [
      for idx, _ in var.secrets : templatefile(
        "${path.module}/secrets.json.tpl",
        {
          name       = element(keys(var.secrets[idx]), 0)
          value      = element(values(var.secrets[idx]), 0)
          region     = var.aws_region
          account_id = data.aws_caller_identity.current.account_id
        }
      )
    ]
  )

  all_ports = concat(
    [{
      host_port      = var.container_port
      container_port = var.container_port
      protocol       = "tcp"
    }],
    var.additional_http_ports,
    var.additional_https_ports,
    var.additional_ports,
  )

  port_mappings = [for p in local.all_ports :
    {
      hostPort      = tonumber(p.host_port)
      containerPort = tonumber(p.container_port)
      protocol      = p.protocol
    }
  ]

  health_check_command = flatten([
    var.health_check_mode,
    var.health_check_mode == "CMD-SHELL" ? [(
      var.task_type == "web_service" ? (
        var.web_service_health_check_command == "" ? local.default_web_service_health_check_command : var.web_service_health_check_command
      ) : var.health_check_command
    )] : var.health_check_command_list
  ])

  mount_points = [for mount_point in var.docker_volume_mount_points :
    {
      sourceVolume  = mount_point.source_volume
      containerPath = mount_point.container_path
      readOnly      = mount_point.read_only
    }
  ]

  log_configuration_options = merge(
    {
      "Name"           = "datadog"
      "Host"           = "http-intake.logs.datadoghq.com"
      "TLS"            = "on"
      "dd_service"     = var.service_name
      "dd_source"      = "${var.environment}-${var.service_name}"
      "dd_tags"        = "env:${var.environment},environment:${var.environment},service_name:${var.service_name}"
      "dd_message_key" = "log"
      "provider"       = "ecs"
      "compress"       = "gzip"
    },
    var.log_configuration_options_override
  )

  firelens_configuration_options = merge(
    {
      "enable-ecs-log-metadata" = "true"
      "config-file-type"        = "file"
      "config-file-value"       = "/fluent-bit/configs/parse-json.conf"
    },
    var.firelens_configuration_options_override
  )

  container_definition_template_vars = {
    aws_region                             = var.aws_region
    account_id                             = data.aws_caller_identity.current.account_id
    environment                            = var.environment
    service_name                           = var.service_name
    application_task_cpu                   = local.application_task_cpu
    application_task_memory                = local.application_task_memory
    container_port                         = var.container_port
    commit_sha                             = var.commit_sha
    datadog_task_cpu                       = var.datadog_task_cpu
    datadog_task_memory                    = var.datadog_task_memory
    datadog_image                          = local.datadog_image
    datadog_api_key                        = data.aws_secretsmanager_secret.datadog_api_key.arn
    docker_labels                          = local.docker_labels
    fluentbit_task_cpu                     = var.fluentbit_task_cpu
    fluentbit_task_memory                  = var.fluentbit_task_memory
    fluentbit_image                        = local.fluentbit_image
    log_router_log_level                   = var.log_router_log_level
    health_check_path                      = var.health_check_path
    health_check_interval                  = var.health_check_interval
    health_check_timeout                   = var.health_check_timeout
    health_check_command                   = local.health_check_command
    health_check_grace_period_seconds      = var.health_check_grace_period_seconds
    container_start_period_seconds         = var.container_start_period_seconds
    ulimit_nofile_soft_limit               = var.ulimit_nofile_soft_limit
    ulimit_nofile_hard_limit               = var.ulimit_nofile_hard_limit
    docker_image                           = local.docker_image
    environment_variables                  = local.environment_variables_combined
    datadog_agent_environment_variables    = local.datadog_agent_environment_variables_combined
    secrets                                = local.secrets_combined
    efs_filesystem_name                    = "${var.environment}-${var.service_name}"
    swf_monitor_task_cpu                   = var.swf_monitor_task_cpu
    swf_monitor_task_memory                = var.swf_monitor_task_memory
    swf_monitor_domain                     = var.swf_monitor_domain
    swf_monitor_workflow_name              = var.swf_monitor_workflow_name
    max_swap                               = var.max_swap
    swappiness                             = var.swappiness
    is_defender_enabled                    = var.defender.enabled
    defender_task_cpu                      = var.defender.task_cpu
    defender_task_memory                   = var.defender.task_memory
    defender_image                         = local.defender_image
    defender_ws_address                    = var.defender.ws_address
    defender_filesystem_monitoring_enabled = var.defender.filesystem_monitoring_enabled
    port_mappings                          = local.port_mappings
    mount_points                           = local.mount_points
    version_consistency                    = local.version_consistency
    log_configuration_options              = local.log_configuration_options
    firelens_configuration_options         = local.firelens_configuration_options
  }

  container_definition_file = var.use_custom_task_definition_file ? var.task_definition_file_location : templatefile(local.default_container_definition_template_file, local.container_definition_template_vars)

  https_listener_allow_cidr_blocks = concat(lookup({
    dev  = var.dev_https_listener_allow_cidr_blocks
    qa   = var.qa_https_listener_allow_cidr_blocks
    prod = var.prod_https_listener_allow_cidr_blocks
  }, var.environment, []), var.https_listener_public_allow_cidr_blocks)

  http_listener_allow_cidr_blocks = concat(lookup({
    dev  = var.dev_http_listener_allow_cidr_blocks
    qa   = var.qa_http_listener_allow_cidr_blocks
    prod = var.prod_http_listener_allow_cidr_blocks
  }, var.environment, []), var.http_listener_public_allow_cidr_blocks)

  https_listener_allow_prefix_lists = concat(lookup({
    dev = [
      "shared-orcd-dev-box-private-subnet-prefix-list",
      "vpn-ny-users"
    ]
    qa = [
      "shared-orcd-dev-box-private-subnet-prefix-list",
      "qa-test-automation-private-subnet-prefix-list",
      "vpn-ny-users"
    ]
    uat = [
      "shared-orcd-dev-box-private-subnet-prefix-list",
      "vpn-ny-users"
    ]
  }, var.environment, []), var.https_listener_allow_prefix_list_names, [for prefix_list in data.aws_ec2_managed_prefix_list.private_subnets : prefix_list.name])

  http_listener_allow_prefix_lists = concat(lookup({
    dev = ["shared-orcd-dev-box-private-subnet-prefix-list"]
    qa = [
      "shared-orcd-dev-box-private-subnet-prefix-list",
      "qa-test-automation-private-subnet-prefix-list"
    ]
  }, var.environment, []), var.http_listener_allow_prefix_list_names, [for prefix_list in data.aws_ec2_managed_prefix_list.private_subnets : prefix_list.name])

  # Mapping of domain names by environment for SSL certificates
  https_listener_domains = {
    dev  = "*.dev.theorchard.io"
    qa   = "*.theorchard.io"
    prod = "*.theorchard.io"
  }

  # Build the certificate domain to use based on passed in https_listener_domain_for_certificate vs mapping by environment
  certificate_domain = (
    var.https_listener_domain_for_certificate == "" ?
    lookup(local.https_listener_domains, var.environment, "*.${var.environment}.theorchard.io") :
    var.https_listener_domain_for_certificate
  )
  # Use the https_listener_certificate_id or use the certificate for the specified domain
  certificate_arn = (
    var.https_listener_certificate_id == "" ?
    length(data.aws_acm_certificate.lb_ssl_certificate) == 0 ? null : data.aws_acm_certificate.lb_ssl_certificate[0].arn :
    "arn:aws:acm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:certificate/${var.https_listener_certificate_id}"
  )

  docker_image = var.non_ecr_image == "" ? "${local.shared_services_account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/${var.service_name}:${var.commit_sha}" : var.non_ecr_image

  waf_type = var.blocking_waf_enabled ? "block" : "count-only"

  current_account_metadata = try(
    [for name, props in module.aws_accounts[0].accounts_map : props if props.account_id == local.account_id][0],
    {}
  )
  account_default_waf_name = try(local.current_account_metadata.default_waf_name, "")
  default_waf_name         = local.account_default_waf_name != "" ? local.account_default_waf_name : "${var.environment}-orcd-waf-${local.waf_type}"

  autoscaling_load_balancer_policy_enabled = var.autoscaling_load_balancer_policy_enabled && var.task_type == "web_service"
  autoscaling_target_enabled               = var.autoscaling_cpu_policy_enabled || var.autoscaling_memory_policy_enabled || local.autoscaling_load_balancer_policy_enabled || var.autoscaling_active_connections_policy_enabled || var.external_autoscaling_policy_enabled

  # Concatenate required and user-supplied tags
  combined_resource_tags = merge(
    {
      environment        = var.environment
      service_name       = var.service_name
      application_family = var.application_family
      terraformed        = true
    },
    var.additional_tags
  )

  docker_labels = merge(
    {
      "environment" : var.environment,
      "com.datadoghq.tags.env" : var.environment,
      "com.datadoghq.tags.service" : var.service_name
    },
    var.additional_docker_labels
  )

  centralized_alb_logs_bucket_name         = var.aws_region == "us-east-1" ? "shared-orcd-lb-logs" : "shared-orcd-lb-logs-${var.aws_region}"
  load_balancer_access_logs_s3_bucket_name = var.enable_centralized_alb_logs ? local.centralized_alb_logs_bucket_name : var.load_balancer_access_logs_s3_bucket_name

  alb_access_logs_bucket_prefix = var.load_balancer_access_logs_prefix != "" ? var.load_balancer_access_logs_prefix : "${local.account_id}/${var.environment}-${var.service_name}"

  additional_task_role_principals_enabled = length(var.additional_task_role_principals) > 0 ? toset(["Enabled"]) : []

  version_consistency          = var.version_consistency ? "enabled" : "disabled"
  permissions_boundary_enabled = coalesce(var.permissions_boundary_enabled, var.environment == "dev" ? true : false)
  permissions_boundary_arn     = local.permissions_boundary_enabled ? data.aws_iam_policy.permissions_boundary_policy[0].arn : null

  # Determine Route53 zone ID based on environment unless overridden
  route53_zone_id = var.override_route53_zone_id != null ? var.override_route53_zone_id : (var.environment == "dev" ? "Z21XEY26C989RH" : "Z0183645HDT0XCWHLW7S")
}

variable "service_platform_version" {
  description = "Specify the platform version for the ecs task"
  default     = "LATEST"
}

variable "ordered_placement_strategy_type" {
  description = "Specify the placement strategy type for the ecs task. Must be one of: binpack, random, or spread."
  default     = "binpack"
}

variable "ordered_placement_strategy_field" {
  description = "Specify the placement strategy field for the ecs task."
  default     = "memory"
}

variable "task_protection_policy_enabled" {
  description = "Enable task protection policy"
  default     = false
}

variable "ecs_network_mode" {
  description = "Specify the network mode for the ecs task. Must be one of: bridge, host, or awsvpc."
  default     = "awsvpc"
}

variable "ecs_requires_compatibilities" {
  description = "Specify the requires compatibilities for the ecs task. Must be one of: EC2, EXTERNAL or FARGATE."
  default = [
    "FARGATE"
  ]
}

variable "ecs_launch_type" {
  description = "Specify the launch type for the ecs task. Must be one of: EC2, EXTERNAL or FARGATE."
  default     = "FARGATE"
}

variable "ecs_cluster_name" {
  description = "Name of the ECS cluster to deploy to. If ecs cluster is already created, this will be the name of the cluster that is created."
  default     = ""
}

variable "stopped_task_monitoring_enabled" {
  description = "Enable reporting of stopped task events to Datadog via EventBridge API connection"
  type        = bool
  default     = false
}

variable "fargate_capacity_provider_base" {
  description = "FARGATE capacity_provider base"
  type        = number
  default     = 0
}

variable "fargate_capacity_provider_weight" {
  description = "FARGATE capacity_provider weight"
  type        = number
  default     = 0
}

variable "fargate_spot_capacity_provider_base" {
  description = "FARGATE_SPOT capacity_provider base"
  type        = number
  default     = 0
}

variable "fargate_spot_capacity_provider_weight" {
  description = "FARGATE_SPOT capacity_provider weight"
  type        = number
  default     = 0
}

variable "task_placement_failure_alert_enabled" {
  description = "Enable reporting of task SERVICE_TASK_PLACEMENT_FAILURE events to Datadog via EventBridge API connection"
  type        = bool
  default     = false
}

variable "additional_task_role_principals" {
  type        = list(string)
  description = "List of ARNs of entities allowed to assume service role (in addition to the ECS itself)"
  default     = []
}

variable "worker_run_task_role_principals" {
  type        = list(string)
  description = "List of ARNs of entities allowed to assume the run task role for worker task types"
  default     = []
}

variable "enable_centralized_alb_logs" {
  type        = bool
  description = "If set to true, ALB logs are sent to the centralized S3 bucket in the AWS shared account (shared-orcd-lb-logs, or shared-orcd-lb-logs-<var.aws_region> outside us-east-1) and variable load_balancer_access_logs_s3_bucket_name is ignored."
  default     = true
}

variable "version_consistency" {
  type        = bool
  description = "Specifies whether Amazon ECS will resolve the container image tag provided in the container definition to an image digest."
  default     = true
}

variable "permissions_boundary_enabled" {
  type        = bool
  description = <<EOF
  Whether or not to set a permissions boundary to limit the permissions of IAM roles created by this module.
  By default, this is true in dev (to allow local Terraform execution) and false in other environments.
  It may be necessary to set this to false in dev if the IAM roles require permissions in excess of those allowed by the permissions boundary policy.
  However, doing so will restrict the ability to run Terraform locally.
EOF
  default     = null
}

variable "permissions_boundary_policy_name" {
  type        = string
  description = "The name of the policy to use as the permissions boundary for the IAM roles created by this module, if permissions_boundary_enabled is true."
  default     = "dev-permissions-boundary-policy"
}

variable "force_new_deployment" {
  type        = bool
  description = "Forces a new deployment of the ECS service."
  default     = null
}
