locals {
  lambda_container_image_uri = "086679231553.dkr.ecr.us-east-1.amazonaws.com/lambda-resonance-engine:latest"

  lambda_common_env = {
    DSQL_ENDPOINT                    = local.dsql_endpoint
    DSQL_TOKEN_EXPIRES_IN            = local.dsql_token_expires_in_s
    REDIS_HOST                       = module.redis_elasticache.redis_primary_endpoint_address
    ENCRYPTION_KEYS_SECRET_NAME      = local.encryption_keys_secret_name
    KAFKA_BOOTSTRAP_SERVERS          = data.aws_msk_cluster.kafka_fansifter.bootstrap_brokers_tls
    KAFKA_TOPIC_FAN_PROFILE          = local.kafka_topics.fanProfile
    KAFKA_TOPIC_FAN_TOP_ARTISTS      = local.kafka_topics.fanTopArtists
    KAFKA_TOPIC_FAN_TOP_TRACKS       = local.kafka_topics.fanTopTracks
    KAFKA_TOPIC_FAN_RECENTLY_PLAYED  = local.kafka_topics.fanRecentlyPlayed
    KAFKA_TOPIC_FAN_PLAYLISTS        = local.kafka_topics.fanPlaylists
    KAFKA_TOPIC_FAN_SAVED_ALBUMS     = local.kafka_topics.fanSavedAlbums
    KAFKA_TOPIC_FAN_SAVED_TRACKS     = local.kafka_topics.fanSavedTracks
    KAFKA_TOPIC_FAN_FOLLOWED_ARTISTS = local.kafka_topics.fanFollowedArtists

    # Spotify: Songwhip
    SPOTIFY_SONGWHIP_CLIENT_ID                 = var.spotify_songwhip_client_id
    SPOTIFY_SONGWHIP_CLIENT_SECRET_NAME        = local.spotify_songwhip_client_secret_name
    SQS_FAN_COLLECT_SPOTIFY_SONGWHIP_QUEUE_URL = module.sqs_fan_collect["spotify-songwhip"].queue_url

    # Spotify: SMF SME
    SPOTIFY_SMF_SME_CLIENT_ID                 = var.spotify_smf_sme_client_id
    SPOTIFY_SMF_SME_CLIENT_SECRET_NAME        = local.spotify_smf_sme_client_secret_name
    SQS_FAN_COLLECT_SPOTIFY_SMF_SME_QUEUE_URL = module.sqs_fan_collect["spotify-smf-sme"].queue_url

    # Spotify: SMF Orch
    SPOTIFY_SMF_ORCH_CLIENT_ID                 = var.spotify_smf_orch_client_id
    SPOTIFY_SMF_ORCH_CLIENT_SECRET_NAME        = local.spotify_smf_orch_client_secret_name
    SQS_FAN_COLLECT_SPOTIFY_SMF_ORCH_QUEUE_URL = module.sqs_fan_collect["spotify-smf-orch"].queue_url

    # Deezer: Songwhip
    SQS_FAN_COLLECT_DEEZER_SONGWHIP_QUEUE_URL = module.sqs_fan_collect["deezer-songwhip"].queue_url

    # Amazon: Songwhip
    AMAZON_SONGWHIP_CLIENT_ID                 = var.amazon_songwhip_client_id
    AMAZON_SONGWHIP_CLIENT_SECRET_NAME        = local.amazon_songwhip_client_secret_name
    AMAZON_SONGWHIP_PROFILE_ID                = var.amazon_songwhip_profile_id
    SQS_FAN_COLLECT_AMAZON_SONGWHIP_QUEUE_URL = module.sqs_fan_collect["amazon-songwhip"].queue_url

    # Apple: Songwhip
    APPLE_SONGWHIP_TEAM_ID                   = var.apple_songwhip_team_id
    APPLE_SONGWHIP_KEY_ID                    = var.apple_songwhip_key_id
    APPLE_SONGWHIP_PRIVATE_KEY_NAME          = local.apple_songwhip_private_key_name
    SQS_FAN_COLLECT_APPLE_SONGWHIP_QUEUE_URL = module.sqs_fan_collect["apple-songwhip"].queue_url

    # Needed by compute_infra_config (fan-fanout, API) to correctly report worker
    # timeout and derived SQS visibility timeout in the /dsp/clients/*/infra-config endpoint.
    FAN_COLLECT_WORKER_TIMEOUT_S = var.fan_collect_worker_timeout_s

    # Must match the fan-fanout EventBridge schedule (both derive from the variable).
    FAN_FANOUT_WINDOW_S = var.fan_fanout_window_s
  }

  lambda_common_policies = [
    aws_iam_policy.dsql_admin.arn,
    aws_iam_policy.encryption_keys_read_policy.arn,
    aws_iam_policy.dsp_secrets_read_policy.arn,
    aws_iam_policy.fan_collect_sqs_send_policy.arn,
  ]

  # DLQ Lambda only needs DB access — no SQS send, no DSP secrets.
  lambda_dlq_policies = [
    aws_iam_policy.dsql_admin.arn,
    aws_iam_policy.encryption_keys_read_policy.arn,
  ]

  # Shared across all fan-collect lambdas (timeout = var.fan_collect_worker_timeout_s).
  fan_collect_memory_size  = 1024
  fan_collect_batch_size   = 1 # one SQS message per invocation
  fan_collect_batch_window = 0

  # Per-client in-flight concurrency budget — see compute_infra_config:
  # ceil(nominal_rps * 0.85 * latency). Queue/timeout/etc. derive from the key.
  fan_collect_lambdas = {
    "spotify-songwhip" = { reserved_concurrent_executions = 3 }
    "spotify-smf-sme"  = { reserved_concurrent_executions = 50 }
    "spotify-smf-orch" = { reserved_concurrent_executions = 50 }
    "deezer-songwhip"  = { reserved_concurrent_executions = 3 }
    "amazon-songwhip"  = { reserved_concurrent_executions = 3 }
    "apple-songwhip"   = { reserved_concurrent_executions = 3 }
  }

}

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

  environment        = var.environment
  platform           = "python"
  service_name       = "lambda-resonance-engine-fan-fanout"
  application_family = var.application_family
}

module "lambda_fan_fanout" {
  source = "git@github.com:theorchard/terraform-lambda.git//?ref=5.3.0"

  environment        = var.environment
  application_family = var.application_family
  lambda_name        = "lambda-resonance-engine-fan-fanout"
  lambda_description = "Resonance Engine fan-fanout entrypoint"

  use_container_image        = true
  container_image_custom_uri = local.lambda_container_image_uri

  lambda_function_timeout                        = 540
  lambda_function_memory_size                    = 512
  lambda_function_reserved_concurrent_executions = 1

  lambda_function_environment_variables = merge(
    local.lambda_common_env,
    {
      ENVIRONMENT                = var.environment
      SERVICE_NAME               = "lambda-resonance-engine-fan-fanout"
      DD_LAMBDA_HANDLER          = "resonance_engine.runtime.main.fan_fanout"
      DD_TRACE_PROPAGATION_STYLE = "none"
      SENTRY_DSN                 = module.lambda_fan_fanout_sentry.sentry_key_dsn_public_output
    },
  )

  iam_managed_policy_attachments = local.lambda_common_policies

  cloudwatch_event_enabled  = true
  cloudwatch_event_schedule = "rate(${floor(var.fan_fanout_window_s / 60)} minutes)"

  vpc_enabled    = true
  vpc_id         = module.vpc_info.vpc_id
  vpc_subnet_ids = module.vpc_info.default_private_subnet_ids

  datadog_enabled          = true
  datadog_advanced_enabled = true
}

module "lambda_fan_fanout_datadog" {
  source = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.13.7"

  environment                       = var.environment
  service_name                      = "lambda-resonance-engine-fan-fanout"
  teams                             = [var.application_family]
  lambda_invocation_monitor_enabled = false

  notification_endpoints            = "@slack-fansifter-alerts"
  escalation_notification_endpoints = "@slack-fansifter"
}

module "fan_collect_lambda_sentry" {
  source   = "git@github.com:theorchard/terraform-sentry.git//?ref=4.1.2"
  for_each = local.fan_collect_lambdas

  environment = var.environment
  platform    = "python"
  # Sentry slug "${env}-${service_name}" is immutable — frozen to the live projects
  # (50-char cap; prod longest spotify-smf-orch = 50, keep labels ≤ 4 chars).
  service_name       = "resonance-engine-fan-collect-${each.key}"
  application_family = var.application_family
}

module "fan_collect_lambda" {
  source   = "git@github.com:theorchard/terraform-lambda.git//?ref=5.3.0"
  for_each = local.fan_collect_lambdas

  environment        = var.environment
  application_family = var.application_family
  lambda_name        = "lambda-resonance-engine-fan-collect-${each.key}"
  lambda_description = "Resonance Engine fan-collect consumer for ${each.key}"

  use_container_image        = true
  container_image_custom_uri = local.lambda_container_image_uri

  lambda_function_timeout                        = var.fan_collect_worker_timeout_s
  lambda_function_memory_size                    = local.fan_collect_memory_size
  lambda_function_reserved_concurrent_executions = each.value.reserved_concurrent_executions

  lambda_function_environment_variables = merge(
    local.lambda_common_env,
    {
      ENVIRONMENT       = var.environment
      SERVICE_NAME      = "lambda-resonance-engine-fan-collect-${each.key}"
      DD_LAMBDA_HANDLER = "resonance_engine.runtime.main.fan_collect"
      SENTRY_DSN        = module.fan_collect_lambda_sentry[each.key].sentry_key_dsn_public_output
    },
  )

  iam_managed_policy_attachments = local.lambda_common_policies

  sqs_event_enabled                 = true
  event_source_mapping_queue_name   = module.sqs_fan_collect[each.key].queue_name
  event_source_mapping_batch_size   = local.fan_collect_batch_size
  event_source_mapping_batch_window = local.fan_collect_batch_window

  vpc_enabled    = true
  vpc_id         = module.vpc_info.vpc_id
  vpc_subnet_ids = module.vpc_info.default_private_subnet_ids

  datadog_enabled          = true
  datadog_advanced_enabled = true
}

module "fan_collect_lambda_datadog" {
  source   = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.13.7"
  for_each = local.fan_collect_lambdas

  environment                       = var.environment
  service_name                      = "lambda-resonance-engine-fan-collect-${each.key}"
  teams                             = [var.application_family]
  lambda_invocation_monitor_enabled = false

  notification_endpoints            = "@slack-fansifter-alerts"
  escalation_notification_endpoints = "@slack-fansifter"
}

# Collect Task DLQ Lambda
# Single Lambda consuming all fan-collect DLQs

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

  environment        = var.environment
  platform           = "python"
  service_name       = "resonance-engine-fan-collect-dlq"
  application_family = var.application_family
}

module "fan_collect_dlq_lambda" {
  source = "git@github.com:theorchard/terraform-lambda.git//?ref=5.3.0"

  environment        = var.environment
  application_family = var.application_family
  lambda_name        = "lambda-resonance-engine-fan-collect-dlq"
  lambda_description = "Resonance Engine fan-collect DLQ handler — marks failed batches stale"

  use_container_image        = true
  container_image_custom_uri = local.lambda_container_image_uri

  lambda_function_timeout     = 60
  lambda_function_memory_size = 256

  lambda_function_environment_variables = merge(
    local.lambda_common_env,
    {
      ENVIRONMENT       = var.environment
      SERVICE_NAME      = "lambda-resonance-engine-fan-collect-dlq"
      DD_LAMBDA_HANDLER = "resonance_engine.runtime.main.fan_collect_dlq"
      SENTRY_DSN        = module.fan_collect_dlq_lambda_sentry.sentry_key_dsn_public_output
    },
  )

  iam_managed_policy_attachments = local.lambda_dlq_policies

  vpc_enabled    = true
  vpc_id         = module.vpc_info.vpc_id
  vpc_subnet_ids = module.vpc_info.default_private_subnet_ids

  datadog_enabled          = true
  datadog_advanced_enabled = true
}

module "fan_collect_dlq_lambda_datadog" {
  source = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.13.7"

  environment                       = var.environment
  service_name                      = "lambda-resonance-engine-fan-collect-dlq"
  teams                             = [var.application_family]
  lambda_invocation_monitor_enabled = false

  notification_endpoints            = "@slack-fansifter-alerts"
  escalation_notification_endpoints = "@slack-fansifter"
}

# Wire the single DLQ Lambda to every fan-collect dead letter queue.
# for_each over sqs_fan_collect so new DSP clients are automatically included
# without any changes here — just add a new entry to fan_collect_queues.
resource "aws_lambda_event_source_mapping" "fan_collect_dlq" {
  for_each = module.sqs_fan_collect

  event_source_arn = each.value.deadletter_queue_arn
  function_name    = module.fan_collect_dlq_lambda.lambda_arn
  batch_size       = 10
  enabled          = true

  depends_on = [aws_iam_role_policy.fan_collect_dlq_sqs_read]
}

# One inline policy for all DLQs — inline doesn't count against the 10-managed-policies-per-role quota.
data "aws_iam_policy_document" "fan_collect_dlq_sqs_read" {
  statement {
    effect = "Allow"
    actions = [
      "sqs:ReceiveMessage",
      "sqs:DeleteMessage",
      "sqs:GetQueueAttributes",
    ]
    resources = [for q in module.sqs_fan_collect : q.deadletter_queue_arn]
  }
}

resource "aws_iam_role_policy" "fan_collect_dlq_sqs_read" {
  name   = "${var.environment}-${var.service_name}-fan-collect-dlq-ReceiveMessage"
  role   = module.fan_collect_dlq_lambda.lambda_role_id
  policy = data.aws_iam_policy_document.fan_collect_dlq_sqs_read.json
}
