
locals {
  presave_stores = keys(var.presave_store_clients)

  presave_store_client_pairs = {
    for pair in flatten([
      for store, clients in var.presave_store_clients : [
        for client in clients : {
          key    = "${store}-${client}"
          store  = store
          client = client
        }
      ]
    ]) : pair.key => pair
  }

  # Provide an empty override with all optional keys to satisfy typing
  empty_presave_override = {
    timeout              = null
    memory_size          = null
    reserved_concurrency = null
    batch_size           = null
    batch_window         = null
    env_overrides        = null
  }

  # Per-DSP defaults with optional overrides from presave_service_configs
  presave_service_config_map = {
    for store in local.presave_stores : store => merge(
      var.presave_service_defaults,
      { for k, v in lookup(var.presave_service_configs, store, local.empty_presave_override) : k => v if v != null }
    )
  }

  # Lambda function names per DSP
  presave_lambda_names = {
    for store in local.presave_stores : store => "lambda-${var.service_name}-${store}"
  }
}

module "songwhip_presaves_lambda_sentry" {
  source   = "git@github.com:theorchard/terraform-sentry//?ref=5.0.0"
  for_each = local.presave_service_config_map

  environment        = var.environment
  teams              = [var.environment]
  service_name       = local.presave_lambda_names[each.key]
  application_family = var.application_family
  platform           = "node"
}

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

  environment        = var.environment
  teams              = [var.environment]
  service_name       = "lambda-${var.service_name}-results-forwarder"
  application_family = var.application_family
  platform           = "node"
}

# Lambda per DSP
module "songwhip_presaves_lambda" {
  source   = "git@github.com:theorchard/terraform-lambda.git//?ref=5.3.0"
  for_each = local.presave_service_config_map

  environment        = var.environment
  lambda_name        = local.presave_lambda_names[each.key]
  lambda_description = "Processes ${each.key} SQS messages and calls DSP APIs for library presaves"
  application_family = var.application_family

  # VPC configuration to reach other services
  vpc_enabled    = true
  vpc_id         = module.vpc_info.vpc_id
  vpc_subnet_ids = module.vpc_info.default_private_subnet_ids

  # Container image for Lambda
  use_container_image = true

  # SQS event source mapping
  sqs_event_enabled = false

  # Function configuration
  lambda_function_timeout                        = each.value.timeout
  lambda_function_memory_size                    = each.value.memory_size
  lambda_function_reserved_concurrent_executions = each.value.reserved_concurrency

  # Error handling (not needed as DLQ is handled by SQS itself)
  dlq_enabled = false

  # Monitoring
  datadog_enabled = true

  lambda_function_environment_variables = merge(
    {
      ENV                                  = var.environment
      NODE_ENV                             = "production"
      SONGWHIP_ENV                         = "production"
      SENTRY_DSN                           = module.songwhip_presaves_lambda_sentry[each.key].sentry_key_dsn_public_output
      PRESAVES_REDIS_HOST                  = module.songwhip_presaves_redis.redis_primary_endpoint_address
      PRESAVES_REDIS_PORT                  = 6379
      PRESAVES_REDIS_USE_TLS               = true
      PRESAVES_KMS_KEY_ID                  = aws_kms_key.songwhip_presaves_kms_key.key_id
      PRESAVES_EXECUTION_RESULTS_QUEUE_URL = module.songwhip_presaves_execution_results_sqs.queue_url
    },
    lookup(each.value, "env_overrides", {})
  )
}

resource "aws_lambda_event_source_mapping" "songwhip_presaves_sqs_event_source" {
  for_each = local.presave_store_client_pairs

  event_source_arn                   = aws_sqs_queue.songwhip_presaves_sqs[each.key].arn
  function_name                      = module.songwhip_presaves_lambda[each.value.store].lambda_arn
  batch_size                         = local.presave_service_config_map[each.value.store].batch_size
  maximum_batching_window_in_seconds = local.presave_service_config_map[each.value.store].batch_window
  enabled                            = true
  function_response_types            = ["ReportBatchItemFailures"]
}

resource "aws_lambda_event_source_mapping" "songwhip_presaves_dlq_event_source" {
  for_each = toset(local.presave_stores)

  event_source_arn                   = aws_sqs_queue.songwhip_presaves_dlq[each.value].arn
  function_name                      = module.songwhip_presaves_results_forwarder.lambda_arn
  batch_size                         = 10
  maximum_batching_window_in_seconds = 3
  enabled                            = true
  function_response_types            = ["ReportBatchItemFailures"]
}

# Lambda for processing presave execution results and forwarding to the presave API
module "songwhip_presaves_results_forwarder" {
  source = "git@github.com:theorchard/terraform-lambda.git//?ref=5.3.0"

  environment        = var.environment
  lambda_name        = "lambda-${var.service_name}-results-forwarder"
  lambda_description = "Forwards presave execution results to the presave API"
  application_family = var.application_family

  # VPC configuration to reach other services
  vpc_enabled    = true
  vpc_id         = module.vpc_info.vpc_id
  vpc_subnet_ids = module.vpc_info.default_private_subnet_ids

  # Container image for Lambda
  use_container_image = true

  # SQS event source mapping
  sqs_event_enabled                   = true
  event_source_mapping_queue_name     = module.songwhip_presaves_execution_results_sqs.queue_name
  event_source_mapping_batch_size     = 100
  event_source_mapping_batch_window   = 10
  event_source_mapping_response_types = ["ReportBatchItemFailures"]

  # Function configuration
  lambda_function_timeout                        = 120
  lambda_function_memory_size                    = 512
  lambda_function_reserved_concurrent_executions = 2

  # Error handling (not needed as DLQ is handled by SQS itself)
  dlq_enabled = false

  # Monitoring
  datadog_enabled = true

  lambda_function_environment_variables = {
    ENV                 = var.environment
    NODE_ENV            = "production"
    SONGWHIP_ENV        = "production"
    AUTH0_M2M_BASE_URL  = var.auth0_m2m_base_url
    AUTH0_M2M_AUDIENCE  = var.auth0_m2m_audience
    AUTH0_M2M_CLIENT_ID = var.auth0_m2m_client_id
    PRESAVES_API_URL    = "https://presaves.aws-prod.songwhip.com"
    SENTRY_DSN          = module.songwhip_presaves_results_forwarder_sentry.sentry_key_dsn_public_output
  }
}

# Grant presave Lambda permission to read from its SQS queue
data "aws_iam_policy_document" "songwhip_presaves_sqs_read_policy_document" {
  for_each = local.presave_store_client_pairs

  statement {
    effect = "Allow"
    actions = [
      "sqs:ReceiveMessage",
      "sqs:DeleteMessage",
      "sqs:ChangeMessageVisibility",
      "sqs:GetQueueAttributes",
    ]
    resources = [aws_sqs_queue.songwhip_presaves_sqs[each.key].arn]
  }
}

resource "aws_iam_policy" "songwhip_presaves_sqs_read_policy" {
  for_each    = data.aws_iam_policy_document.songwhip_presaves_sqs_read_policy_document
  name        = "${var.environment}-${var.service_name}-${each.key}-sqs-read"
  description = "Allow presave Lambdas to read from ${each.key} SQS queue"
  policy      = each.value.json
}

resource "aws_iam_role_policy_attachment" "songwhip_presaves_lambda_policy" {
  for_each = local.presave_store_client_pairs

  role       = module.songwhip_presaves_lambda[each.value.store].lambda_role_id
  policy_arn = aws_iam_policy.songwhip_presaves_sqs_read_policy[each.key].arn
}

# Grant presave Lambda permission to write to the executions SQS queue
resource "aws_iam_role_policy_attachment" "songwhip_presaves_lambda_execution_results_sqs_policy" {
  for_each = module.songwhip_presaves_lambda

  role       = each.value.lambda_role_id
  policy_arn = aws_iam_policy.songwhip_presaves_execution_results_sqs_send_policy.arn
}

# Grant presave Lambda permission to decrypt sensitive fields with KMS
resource "aws_iam_role_policy_attachment" "songwhip_presaves_lambda_kms_attachment" {
  for_each = module.songwhip_presaves_lambda

  role       = each.value.lambda_role_id
  policy_arn = aws_iam_policy.songwhip_presaves_kms_decrypt_only_policy.arn
}

# Grant result forwarder Lambda permission to read from its SQS queue
resource "aws_iam_role_policy_attachment" "songwhip_presaves_results_forwarder_policy" {
  role       = module.songwhip_presaves_results_forwarder.lambda_role_id
  policy_arn = module.songwhip_presaves_execution_results_sqs.sqs_minimal_policy_arn_output
}

# Grant result forwarder Lambda permission to read from presave DLQs
data "aws_iam_policy_document" "songwhip_presaves_execution_results_dlq_read_policy_document" {
  statement {
    effect = "Allow"
    actions = [
      "sqs:ReceiveMessage",
      "sqs:DeleteMessage",
      "sqs:ChangeMessageVisibility",
      "sqs:GetQueueAttributes",
    ]
    resources = [for store in local.presave_stores : aws_sqs_queue.songwhip_presaves_dlq[store].arn]
  }
}

resource "aws_iam_policy" "songwhip_presaves_execution_results_dlq_read_policy" {
  name        = "${var.environment}-${var.service_name}-presaves-dlq-read"
  description = "Allow executions Lambda to read from presave DLQs"
  policy      = data.aws_iam_policy_document.songwhip_presaves_execution_results_dlq_read_policy_document.json
}

resource "aws_iam_role_policy_attachment" "songwhip_presaves_results_forwarder_dlq_policy" {
  role       = module.songwhip_presaves_results_forwarder.lambda_role_id
  policy_arn = aws_iam_policy.songwhip_presaves_execution_results_dlq_read_policy.arn
}

# Allow all presave Lambdas to read Secrets Manager entries for this service
data "aws_iam_policy_document" "songwhip_presaves_secrets_read" {
  statement {
    effect = "Allow"
    actions = [
      "secretsmanager:GetSecretValue",
      "secretsmanager:DescribeSecret",
    ]

    resources = [for secret in values(module.songwhip_presaves_secrets) : secret.secret_arn]
  }
}

resource "aws_iam_policy" "songwhip_presaves_secrets_read" {
  name        = "${var.environment}-${var.service_name}-secrets-read"
  description = "Allow presave Lambdas to read presaves Secrets Manager secrets"
  policy      = data.aws_iam_policy_document.songwhip_presaves_secrets_read.json
}

resource "aws_iam_role_policy_attachment" "songwhip_presaves_lambda_secrets_policy" {
  for_each = module.songwhip_presaves_lambda

  role       = each.value.lambda_role_id
  policy_arn = aws_iam_policy.songwhip_presaves_secrets_read.arn
}

resource "aws_iam_role_policy_attachment" "songwhip_presaves_results_forwarder_secrets_policy" {
  role       = module.songwhip_presaves_results_forwarder.lambda_role_id
  policy_arn = aws_iam_policy.songwhip_presaves_secrets_read.arn
}

# Datadog monitors per presave Lambda
module "songwhip_presaves_lambda_datadog_monitor" {
  source   = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.18.1"
  for_each = module.songwhip_presaves_lambda

  service_name = local.presave_lambda_names[each.key]
  environment  = var.environment
  teams        = [var.team_name]

  # This lambda will not run very often so we can disable invocation monitoring
  lambda_invocation_monitor_enabled = false

  notification_endpoints            = "@slack-songwhip-alerts"
  escalation_notification_endpoints = "@slack-songwhip-private"
}

# Datadog monitors for executions Lambda
module "songwhip_presaves_results_forwarder_datadog_monitor" {
  source = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.18.1"

  service_name = "lambda-${var.service_name}-results-forwarder"
  environment  = var.environment
  teams        = [var.team_name]

  # This lambda will not run very often so we can disable invocation monitoring
  lambda_invocation_monitor_enabled = false

  notification_endpoints            = "@slack-songwhip-alerts"
  escalation_notification_endpoints = "@slack-songwhip-private"
}
