data "archive_file" "lambda_package" {
  count       = var.update_lambda_code ? 1 : 0
  type        = "zip"
  source_file = "${path.module}/lambda_function.py"
  output_path = "${path.module}/lambda_function.zip"
  depends_on  = [local_file.lambda-function]
}

locals {
  lambda_filename = var.update_lambda_code ? data.archive_file.lambda_package[0].output_path : "${path.module}/lambda_function.zip"
}

data "aws_region" "eu-central" {
  provider = aws.eu-central-1
}

resource "aws_lambda_function" "monitor-rds-subnet-ips" {
  #checkov:skip=CKV_AWS_50: X-ray tracing is enabled for Lambda. Migrated existing lambda as-is.
  #checkov:skip=CKV_AWS_115: Ensure that AWS Lambda function is configured for function-level concurrent execution limit. Migrated existing lambda as-is.
  #checkov:skip=CKV_AWS_116: Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ). Migrated existing lambda as-is.
  #checkov:skip=CKV_AWS_117: Ensure that AWS Lambda function is configured inside a VPC. Migrated existing lambda as-is.
  #checkov:skip=CKV_AWS_173: Check encryption settings for Lambda environmental variable. Migrated existing lambda as-is.
  #checkov:skip=CKV_AWS_272: Ensure AWS Lambda function is configured to validate code-signing. Migrated existing lambda as-is.
  provider         = aws.eu-central-1
  function_name    = "MonitorRDSSubnetIPs"
  runtime          = "python3.14"
  handler          = "datadog_lambda.handler.handler"
  role             = "arn:aws:iam::${var.account_id}:role/lambda-monitor-rds-subnet-ips-role"
  filename         = local.lambda_filename
  memory_size      = 128
  timeout          = 30
  source_code_hash = var.update_lambda_code ? base64sha256("FORCE-UPDATE-${uuid()}") : null

  layers = [
    "arn:aws:lambda:eu-central-1:464622532012:layer:Datadog-Python38:105",
    "arn:aws:lambda:eu-central-1:464622532012:layer:Datadog-Extension:71"
  ]
  environment {
    variables = {
      SUBNET_IDS                   = join(",", var.monitored_subnet_ids),
      DD_LAMBDA_HANDLER            = "lambda_function.lambda_handler",
      DD_TRACE_ENABLED             = "true",
      DD_API_KEY_SECRET_ARN        = "arn:aws:secretsmanager:eu-central-1:${var.account_id}:secret:${var.environment}/datadog/DD_API_KEY",
      DD_SITE                      = "datadoghq.com",
      DD_SERVERLESS_LOGS_ENABLED   = "true",
      DD_ENV                       = "prod",
      DD_SERVICE                   = "subnet-ip-monitoring",
      DD_TRACE_OTEL_ENABLED        = "false",
      DD_PROFILING_ENABLED         = "false",
      DD_SERVERLESS_APPSEC_ENABLED = "false",
      DD_FLUSH_TO_LOG              = "false"
    }
  }
}

resource "aws_cloudwatch_event_rule" "lambda-schedule" {
  provider            = aws.eu-central-1
  name                = "MonitorRDSSubnetIPsRule"
  schedule_expression = "rate(1 minute)"
}

resource "aws_cloudwatch_event_target" "lambda-target" {
  provider  = aws.eu-central-1
  rule      = aws_cloudwatch_event_rule.lambda-schedule.name
  target_id = "MonitorRDSSubnetIPsTarget"
  arn       = aws_lambda_function.monitor-rds-subnet-ips.arn
}

resource "aws_lambda_permission" "allow-eventbridge" {
  provider      = aws.eu-central-1
  statement_id  = "AllowExecutionFromEventBridge"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.monitor-rds-subnet-ips.function_name
  principal     = "events.amazonaws.com"
  source_arn    = aws_cloudwatch_event_rule.lambda-schedule.arn
}

resource "local_file" "lambda-function" {
  count    = var.update_lambda_code ? 1 : 0
  content  = <<EOF
import boto3
import os
from datadog_lambda.metric import lambda_metric
from datadog_lambda.wrapper import datadog_lambda_wrapper

# Environment Variables
SUBNET_IDS = os.getenv("SUBNET_IDS", "").split(",")

@datadog_lambda_wrapper
def lambda_handler(event, context):
    # Use region from Lambda environment
    region = os.environ.get("AWS_REGION", "eu-central-1")
    ec2 = boto3.client('ec2', region_name=region)
    
    if not SUBNET_IDS or SUBNET_IDS == [""]:
        print("No subnets configured. Exiting.")
        return {"status": "No subnets configured"}

    try:
        response = ec2.describe_subnets(SubnetIds=SUBNET_IDS)

        for subnet in response['Subnets']:
            subnet_id = subnet['SubnetId']
            available_ips = subnet['AvailableIpAddressCount']
            
            # Send metric to Datadog
            lambda_metric(
                metric_name="vpc.subnet.available_ips",
                value=available_ips,
                tags=[f"subnet_id:{subnet_id}"]
            )
            print(f"Subnet {subnet_id}: {available_ips} IPs available")

        return {"status": "Metrics sent to Datadog"}
    except Exception as e:
        print(f"Error: {str(e)}")
        return {"status": "Error", "message": str(e)}
EOF
  filename = "lambda_function.py"
}

# TODO: Needs to be migrated to another Datadog tenant.
# resource "datadog_monitor" "subnet-low-ip-alert" {
#   count = length(var.monitored_subnet_ids)

#   name                = "${upper(var.project_name)} - ${upper(var.environment)} - RDS - ${var.subnet_group_name} - Subnet available IPs - ${var.monitored_subnet_ids[count.index]}"
#   type                = "metric alert"
#   query               = "min(last_5m):vpc.subnet.available_ips{subnet_id:${var.monitored_subnet_ids[count.index]}} < 2"
#   message             = <<EOF
# {{#is_alert}}
# Subnet ${var.monitored_subnet_ids[count.index]} in subnet group ${var.subnet_group_name} has critically low IP addresses available (less than {{threshold}}). Immediate action required.
# PRIORITY=MEDIUM {{/is_alert}}
# {{#is_recovery}}
# Subnet ${var.monitored_subnet_ids[count.index]} in subnet group ${var.subnet_group_name} has adequate IP addresses available now (at least {{threshold}}).
# PRIORITY=MEDIUM {{/is_recovery}}
# @cloudops.support@sonymusic.com
# @anthony.vitale@sonymusic.com
# EOF
#   tags                = ["${upper(var.project_name)}", "${upper(var.environment)}", "RDS", "Subnets", "managed-by:terraform", "subnet_group:${var.subnet_group_name}"]
#   priority            = 2
#   notify_no_data      = true
#   no_data_timeframe   = 20
#   require_full_window = false

#   monitor_thresholds {
#     critical = 2
#     warning  = 4
#   }
# }
