locals {
  spatial_audio_validation_service_name = "spatial-audio-validation"
  spatial_audio_validation_full_name    = format("%s-%s", var.lambda_service_name, local.spatial_audio_validation_service_name)

  # 2x the 15-min Lambda max we were worried about exceeding when streaming
  # large Atmos assets for signal analysis.
  spatial_audio_validation_message_processing_timeout_minutes = 30

  # Worst acceptable queue-wait window before a worker picks up a message.
  # Once picked up, the worker's first heartbeat resets this clock and the
  # background heartbeat thread keeps it reset for the rest of processing.
  # Each SFN attempt has its own HeartbeatSeconds window; sized to cover the
  # time to scale the worker pool up to meet new queue demand — whether from
  # a cold start (pool at zero) or a spike beyond current capacity. Budget:
  # SQS → CloudWatch scaling alarm latency (~60-120s) plus a Fargate task
  # cold start (35s-2min per AWS:
  # https://docs.aws.amazon.com/decision-guides/latest/fargate-or-lambda/fargate-or-lambda.html).
  spatial_audio_validation_heartbeat_seconds = 180

  # How often the worker pings SFN. Shorter = faster detection of stale /
  # cancelled tokens so stale messages get skipped and in-progress workers can abort.
  spatial_audio_validation_heartbeat_interval_seconds = 15
}

check "spatial_audio_validation_heartbeat_fits_in_processing_timeout" {
  assert {
    condition = local.spatial_audio_validation_heartbeat_seconds * 2 <= local.spatial_audio_validation_message_processing_timeout_minutes * 60
    error_message = format(
      "spatial_audio_validation_heartbeat_seconds (%ds) must be at most half of spatial_audio_validation_message_processing_timeout_minutes (%d min = %ds).",
      local.spatial_audio_validation_heartbeat_seconds,
      local.spatial_audio_validation_message_processing_timeout_minutes,
      local.spatial_audio_validation_message_processing_timeout_minutes * 60,
    )
  }
}

check "spatial_audio_validation_heartbeat_interval_fits_in_heartbeat_window" {
  assert {
    condition = local.spatial_audio_validation_heartbeat_interval_seconds * 2 <= local.spatial_audio_validation_heartbeat_seconds
    error_message = format(
      "spatial_audio_validation_heartbeat_interval_seconds (%ds) must be at most half of spatial_audio_validation_heartbeat_seconds (%ds) so one missed heartbeat doesn't trip SFN's timeout.",
      local.spatial_audio_validation_heartbeat_interval_seconds,
      local.spatial_audio_validation_heartbeat_seconds,
    )
  }
}

data "aws_iam_policy_document" "spatial_audio_validation_s3_read" {
  statement {
    effect  = "Allow"
    actions = ["s3:GetObject"]
    resources = [
      "arn:aws:s3:::${var.environment}-${var.raw_assets_s3_bucket_suffix}/*",
      "arn:aws:s3:::${var.environment}-${var.mezzanine_assets_s3_bucket_suffix}/*",
    ]
  }
}

resource "aws_iam_policy" "spatial_audio_validation_s3_read" {
  name   = "S3-${var.environment}-${local.spatial_audio_validation_full_name}-RO"
  policy = data.aws_iam_policy_document.spatial_audio_validation_s3_read.json
}

module "lambda_assets_spatial_audio_validation_sentry_project" {
  source = "git@github.com:theorchard/terraform-sentry.git?ref=5.0.0"

  environment        = var.environment
  service_name       = local.spatial_audio_validation_full_name
  application_family = var.application_family
}

resource "aws_sqs_queue" "spatial_audio_validation" {
  name = "${var.environment}-${local.spatial_audio_validation_full_name}"

  visibility_timeout_seconds = local.spatial_audio_validation_message_processing_timeout_minutes * 60
  message_retention_seconds  = local.spatial_audio_validation_message_processing_timeout_minutes * 60
  receive_wait_time_seconds  = 20
  sqs_managed_sse_enabled    = true
}

data "aws_iam_policy_document" "spatial_audio_validation_sqs_consumer" {
  statement {
    effect = "Allow"
    actions = [
      "sqs:ReceiveMessage",
      "sqs:DeleteMessage",
      "sqs:ChangeMessageVisibility",
      "sqs:GetQueueAttributes",
      "sqs:GetQueueUrl",
    ]
    resources = [aws_sqs_queue.spatial_audio_validation.arn]
  }
}

resource "aws_iam_policy" "spatial_audio_validation_sqs_consumer" {
  name        = "SQS-${var.environment}-${local.spatial_audio_validation_full_name}-consumer"
  description = "Allow the spatial-audio-validation worker to consume messages from its SQS queue"
  policy      = data.aws_iam_policy_document.spatial_audio_validation_sqs_consumer.json
}

data "aws_iam_policy_document" "spatial_audio_validation_sfn_callback" {
  statement {
    effect = "Allow"
    actions = [
      "states:SendTaskSuccess",
      "states:SendTaskFailure",
      "states:SendTaskHeartbeat",
    ]
    resources = [aws_sfn_state_machine.state_machine.arn]
  }
}

resource "aws_iam_policy" "spatial_audio_validation_sfn_callback" {
  name        = "SFN-${var.environment}-${local.spatial_audio_validation_full_name}-callback"
  description = "Allow the spatial-audio-validation worker to return results via SFN task tokens"
  policy      = data.aws_iam_policy_document.spatial_audio_validation_sfn_callback.json
}

module "lambda_assets_spatial_audio_validation_fargate_environment" {
  source = "git@github.com:theorchard/terraform-fargate.git//?ref=6.5.0"

  providers = {
    aws.dns = aws.networking
  }

  environment                                 = var.environment
  service_name                                = local.spatial_audio_validation_full_name
  aws_region                                  = var.aws_region
  application_family                          = var.application_family
  task_type                                   = "worker"
  health_check_command                        = "python --version"
  deployment_minimum_healthy_percent          = "100"
  autoscaling_cpu_policy_enabled              = false
  external_autoscaling_policy_enabled         = true
  task_protection_policy_enabled              = true
  stopped_task_monitoring_enabled             = true
  deployment_circuit_breaker_enabled          = true
  deployment_circuit_breaker_rollback_enabled = true
  desired_task_count                          = 0
  minimum_capacity                            = 0
  maximum_capacity                            = local.max_concurrency
  # Per message the worker renders the master to two layouts — 0+5+0 (loudness/true-peak) and 0+2+0
  # (alignment) — from one shared ADM parse, sequentially. A single render peaks ~2.2 GB on dense
  # masters (the ADM preprocess dominates, not the audio; ~2.3 GB worst case measured across 21 real
  # masters). 4096 leaves ~3.8 GB after the datadog/fluentbit sidecars — ~1.5x headroom over that peak.
  # 1 vCPU suffices: the render is single-threaded, so extra cores can't speed the critical-path
  # render — they would only overlap the short second render (~8 s on heavy masters).
  task_cpu                                    = 1024
  task_memory                                 = 4096
  health_check_grace_period_seconds           = 300
  container_start_period_seconds              = 300
  vpc_id                                      = module.vpc_info.vpc_id
  fargate_service_subnets                     = module.vpc_info.default_private_subnet_ids
  splitio_enabled                             = false

  environment_variables = [
    {
      ENVIRONMENT = var.environment
    },
    {
      SENTRY_DSN = module.lambda_assets_spatial_audio_validation_sentry_project.sentry_key_dsn_public_output
    },
    {
      SQS_QUEUE_URL = aws_sqs_queue.spatial_audio_validation.url
    },
    {
      MESSAGE_PROCESSING_TIMEOUT_MINUTES = tostring(local.spatial_audio_validation_message_processing_timeout_minutes)
    },
    {
      HEARTBEAT_INTERVAL_SECONDS = tostring(local.spatial_audio_validation_heartbeat_interval_seconds)
    },
  ]

  iam_managed_policy_attachments = [
    aws_iam_policy.spatial_audio_validation_s3_read.arn,
    aws_iam_policy.spatial_audio_validation_sqs_consumer.arn,
    aws_iam_policy.spatial_audio_validation_sfn_callback.arn,
  ]
}

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

  environment        = var.environment
  service_name       = local.spatial_audio_validation_full_name
  application_family = var.application_family
}

resource "aws_cloudwatch_metric_alarm" "spatial_audio_validation_queue_visible_messages" {
  alarm_name        = "SQS-${var.environment}-${local.spatial_audio_validation_full_name}-visible-message-alarm"
  alarm_description = "SQS-${var.environment}-${local.spatial_audio_validation_full_name}-visible-message-alarm"
  namespace         = "AWS/SQS"
  metric_name       = "ApproximateNumberOfMessagesVisible"
  statistic         = "Maximum"

  dimensions = {
    QueueName = aws_sqs_queue.spatial_audio_validation.name
  }

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

  alarm_actions             = [aws_appautoscaling_policy.spatial_audio_validation_scale_up.arn]
  insufficient_data_actions = []
  ok_actions                = [aws_appautoscaling_policy.spatial_audio_validation_scale_down.arn]
}

resource "aws_appautoscaling_policy" "spatial_audio_validation_scale_up" {
  name               = "${var.environment}-${local.spatial_audio_validation_full_name}-sqs-scale-up"
  policy_type        = "StepScaling"
  service_namespace  = "ecs"
  resource_id        = "service/${module.lambda_assets_spatial_audio_validation_fargate_environment.fargate_cluster_name}/${module.lambda_assets_spatial_audio_validation_fargate_environment.fargate_worker_service_name}"
  scalable_dimension = "ecs:service:DesiredCount"

  step_scaling_policy_configuration {
    adjustment_type         = "ChangeInCapacity"
    cooldown                = 30
    metric_aggregation_type = "Maximum"

    step_adjustment {
      metric_interval_lower_bound = 0
      scaling_adjustment          = 1
    }
  }

  depends_on = [module.lambda_assets_spatial_audio_validation_fargate_environment]
}

resource "aws_appautoscaling_policy" "spatial_audio_validation_scale_down" {
  name               = "${var.environment}-${local.spatial_audio_validation_full_name}-sqs-scale-down"
  policy_type        = "StepScaling"
  service_namespace  = "ecs"
  resource_id        = "service/${module.lambda_assets_spatial_audio_validation_fargate_environment.fargate_cluster_name}/${module.lambda_assets_spatial_audio_validation_fargate_environment.fargate_worker_service_name}"
  scalable_dimension = "ecs:service:DesiredCount"

  step_scaling_policy_configuration {
    adjustment_type         = "ChangeInCapacity"
    cooldown                = 30
    metric_aggregation_type = "Maximum"

    step_adjustment {
      metric_interval_upper_bound = 0
      scaling_adjustment          = -1
    }
  }

  depends_on = [module.lambda_assets_spatial_audio_validation_fargate_environment]
}
