# ==============================================================================
# Songwhip MediaConvert Infrastructure
# ==============================================================================
#
# This configuration manages the MediaConvert transcoding infrastructure for
# Songwhip, including:
#   - MediaConvert IAM service role for S3 access
#   - SNS topic for job status notifications
#   - Lambda 1 (trigger): Triggered by S3 uploads, creates MediaConvert jobs
#   - Lambda 2 (status): Triggered by SNS, handles job completion/errors
#
# Architecture:
#   S3 Upload → Lambda Trigger → MediaConvert → SNS → Lambda Status → S3 Tagging
#
# ==============================================================================

provider "aws" {
  region = var.region
}

terraform {
  backend "s3" {
    bucket  = "qa-songwhip-terraform-state"
    key     = "qa/songwhip-mediaconvert/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

data "aws_caller_identity" "current" {}

# Reference to existing content bucket
data "aws_s3_bucket" "songwhip_content" {
  bucket = "qa-songwhip-content"
}

# Reference to HLS output bucket
data "aws_s3_bucket" "songwhip_hls_content" {
  bucket = "qa-songwhip-hls-content"
}

# ==============================================================================
# SHARED INFRASTRUCTURE
# ==============================================================================
#
# Resources shared by both Lambda functions:
#   - MediaConvert IAM service role
#   - SNS topic for job notifications
#
# ==============================================================================

# ------------------------------------------------------------------------------
# MediaConvert IAM Service Role
# Used by MediaConvert to access S3 buckets during transcoding
# ------------------------------------------------------------------------------

data "aws_iam_policy_document" "mediaconvert_assume_role_policy" {
  statement {
    effect = "Allow"

    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type        = "Service"
      identifiers = ["mediaconvert.amazonaws.com"]
    }
  }
}

resource "aws_iam_role" "mediaconvert_role" {
  name               = "${var.environment}-songwhip-mediaconvert-role"
  assume_role_policy = data.aws_iam_policy_document.mediaconvert_assume_role_policy.json
}

# S3 read access to source bucket (uploads prefix)
data "aws_iam_policy_document" "mediaconvert_s3_source_readonly" {
  statement {
    effect = "Allow"

    actions = [
      "s3:GetObject",
      "s3:GetObjectVersion",
      "s3:HeadObject",
    ]

    resources = [
      "${data.aws_s3_bucket.songwhip_content.arn}/uploads/*",
    ]
  }

  statement {
    effect = "Allow"

    actions = [
      "s3:ListBucket",
    ]

    resources = [
      data.aws_s3_bucket.songwhip_content.arn,
    ]
  }
}

resource "aws_iam_policy" "mediaconvert_s3_source_readonly" {
  name   = "S3-${var.environment}-songwhip-content-uploads-RO"
  policy = data.aws_iam_policy_document.mediaconvert_s3_source_readonly.json
}

resource "aws_iam_role_policy_attachment" "mediaconvert_s3_source_readonly" {
  role       = aws_iam_role.mediaconvert_role.id
  policy_arn = aws_iam_policy.mediaconvert_s3_source_readonly.arn
}

# S3 write access to HLS output bucket
data "aws_iam_policy_document" "mediaconvert_s3_destination_write" {
  statement {
    effect = "Allow"

    actions = [
      "s3:PutObject",
      "s3:PutObjectAcl",
      "s3:PutObjectTagging",
    ]

    resources = [
      "${data.aws_s3_bucket.songwhip_hls_content.arn}/*",
    ]
  }

  statement {
    effect = "Allow"

    actions = [
      "s3:ListBucket",
    ]

    resources = [
      data.aws_s3_bucket.songwhip_hls_content.arn,
    ]
  }
}

resource "aws_iam_policy" "mediaconvert_s3_destination_write" {
  name   = "S3-${var.environment}-songwhip-hls-content-RW"
  policy = data.aws_iam_policy_document.mediaconvert_s3_destination_write.json
}

resource "aws_iam_role_policy_attachment" "mediaconvert_s3_destination_write" {
  role       = aws_iam_role.mediaconvert_role.id
  policy_arn = aws_iam_policy.mediaconvert_s3_destination_write.arn
}

# ------------------------------------------------------------------------------
# EventBridge Rule for MediaConvert Job Status
# MediaConvert sends status updates via EventBridge, not directly to SNS
# ------------------------------------------------------------------------------

resource "aws_cloudwatch_event_rule" "mediaconvert_status" {
  name        = "${var.environment}-songwhip-mediaconvert-status"
  description = "Capture MediaConvert job state changes for Songwhip"

  event_pattern = jsonencode({
    source      = ["aws.mediaconvert"]
    detail-type = ["MediaConvert Job State Change"]
    detail = {
      userMetadata = {
        Source = ["songwhip-encrypted-content"]
      }
    }
  })
}

resource "aws_cloudwatch_event_target" "mediaconvert_to_lambda" {
  rule      = aws_cloudwatch_event_rule.mediaconvert_status.name
  target_id = "InvokeStatusLambda"
  arn       = module.status_lambda.lambda_arn
}

# Lambda permission for EventBridge to invoke
resource "aws_lambda_permission" "allow_eventbridge_invoke_status_lambda" {
  statement_id  = "AllowExecutionFromEventBridge"
  action        = "lambda:InvokeFunction"
  function_name = module.status_lambda.lambda_name
  principal     = "events.amazonaws.com"
  source_arn    = aws_cloudwatch_event_rule.mediaconvert_status.arn
}

# ==============================================================================
# LAMBDA 1: MEDIACONVERT TRIGGER
# ==============================================================================
#
# Purpose: Creates MediaConvert transcoding jobs when files are uploaded
#
# Trigger:  S3 ObjectCreated events from qa-songwhip-content/uploads/*
# Actions:  - Validates file format
#           - Creates MediaConvert job with HLS output configuration
#           - Configures job to send status updates to SNS topic
#
# Resources:
#   - Sentry project for error tracking
#   - Lambda function (container-based, no VPC)
#   - IAM policies (MediaConvert, PassRole, S3 read)
#   - Datadog monitors
#
# ==============================================================================

locals {
  trigger_lambda_name = "lambda-songwhip-mediaconvert-trigger"
}

# Sentry project for error tracking
module "trigger_lambda_sentry" {
  source = "git@github.com:theorchard/terraform-sentry//?ref=5.0.0"

  environment        = var.environment
  teams              = [var.environment]
  service_name       = local.trigger_lambda_name
  application_family = var.application_family
  platform           = "node"
}

# Lambda function configuration
module "trigger_lambda" {
  source = "git@github.com:theorchard/terraform-lambda.git//?ref=5.2.1"

  environment        = var.environment
  lambda_name        = local.trigger_lambda_name
  lambda_description = "Creates MediaConvert jobs when files are uploaded to songwhip-content"
  application_family = var.application_family

  # Container image for Lambda
  use_container_image = true
  vpc_enabled         = false

  # S3 event source
  s3_event_enabled       = true
  s3_event_bucket_name   = data.aws_s3_bucket.songwhip_content.id
  s3_event_filter_prefix = "uploads/"

  # Function configuration
  lambda_function_timeout     = 60 # 1 minute (just needs to trigger job)
  lambda_function_memory_size = 512

  # Error handling
  dlq_enabled = true
  dlq_type    = "sns"

  # Monitoring
  datadog_enabled          = true
  datadog_advanced_enabled = false

  lambda_function_environment_variables = {
    MEDIACONVERT_ROLE_ARN = aws_iam_role.mediaconvert_role.arn
    MEDIACONVERT_QUEUE    = "arn:aws:mediaconvert:${var.region}:${data.aws_caller_identity.current.account_id}:queues/Default"
    SOURCE_BUCKET         = data.aws_s3_bucket.songwhip_content.id
    DESTINATION_BUCKET    = data.aws_s3_bucket.songwhip_hls_content.id
    SENTRY_DSN            = module.trigger_lambda_sentry.sentry_key_dsn_public_output
    ENV                   = var.environment
  }
}

# ------------------------------------------------------------------------------
# S3 Event Notification Configuration
# Connects S3 bucket to trigger Lambda
# ------------------------------------------------------------------------------

resource "aws_s3_bucket_notification" "songwhip_content_notification" {
  bucket = data.aws_s3_bucket.songwhip_content.id

  lambda_function {
    lambda_function_arn = module.trigger_lambda.lambda_arn
    events              = ["s3:ObjectCreated:*"]
    filter_prefix       = "uploads/"
  }

  depends_on = [module.trigger_lambda]
}

# ------------------------------------------------------------------------------
# IAM Policies for Trigger Lambda
# ------------------------------------------------------------------------------

# MediaConvert permissions
data "aws_iam_policy_document" "trigger_lambda_mediaconvert" {
  statement {
    effect = "Allow"

    actions = [
      "mediaconvert:CreateJob",
      "mediaconvert:GetJob",
    ]

    resources = [
      "arn:aws:mediaconvert:${var.region}:${data.aws_caller_identity.current.account_id}:*",
    ]
  }
}

resource "aws_iam_policy" "trigger_lambda_mediaconvert" {
  name   = "MediaConvert-${var.environment}-songwhip-trigger-lambda"
  policy = data.aws_iam_policy_document.trigger_lambda_mediaconvert.json
}

resource "aws_iam_role_policy_attachment" "trigger_lambda_mediaconvert" {
  role       = module.trigger_lambda.lambda_role_id
  policy_arn = aws_iam_policy.trigger_lambda_mediaconvert.arn
}

# PassRole permission for MediaConvert role
data "aws_iam_policy_document" "trigger_lambda_pass_role" {
  statement {
    effect = "Allow"

    actions = [
      "iam:PassRole",
    ]

    resources = [
      aws_iam_role.mediaconvert_role.arn,
    ]
  }
}

resource "aws_iam_policy" "trigger_lambda_pass_role" {
  name   = "IAM-${var.environment}-songwhip-mediaconvert-pass-role"
  policy = data.aws_iam_policy_document.trigger_lambda_pass_role.json
}

resource "aws_iam_role_policy_attachment" "trigger_lambda_pass_role" {
  role       = module.trigger_lambda.lambda_role_id
  policy_arn = aws_iam_policy.trigger_lambda_pass_role.arn
}

# S3 read access to source bucket
data "aws_iam_policy_document" "trigger_lambda_s3_source" {
  statement {
    effect = "Allow"

    actions = [
      "s3:GetObject",
      "s3:GetObjectVersion",
    ]

    resources = [
      "${data.aws_s3_bucket.songwhip_content.arn}/uploads/*",
    ]
  }
}

resource "aws_iam_policy" "trigger_lambda_s3_source" {
  name   = "S3-${var.environment}-songwhip-trigger-lambda-source-RO"
  policy = data.aws_iam_policy_document.trigger_lambda_s3_source.json
}

resource "aws_iam_role_policy_attachment" "trigger_lambda_s3_source" {
  role       = module.trigger_lambda.lambda_role_id
  policy_arn = aws_iam_policy.trigger_lambda_s3_source.arn
}

# S3 write access to HLS bucket for encryption keys
data "aws_iam_policy_document" "trigger_lambda_hls_keys_write" {
  statement {
    effect = "Allow"

    actions = [
      "s3:PutObject",
    ]

    resources = [
      "${data.aws_s3_bucket.songwhip_hls_content.arn}/keys/*",
    ]
  }
}

resource "aws_iam_policy" "trigger_lambda_hls_keys_write" {
  name   = "S3-${var.environment}-songwhip-trigger-lambda-hls-keys-write"
  policy = data.aws_iam_policy_document.trigger_lambda_hls_keys_write.json
}

resource "aws_iam_role_policy_attachment" "trigger_lambda_hls_keys_write" {
  role       = module.trigger_lambda.lambda_role_id
  policy_arn = aws_iam_policy.trigger_lambda_hls_keys_write.arn
}

# ------------------------------------------------------------------------------
# Monitoring for Trigger Lambda
# ------------------------------------------------------------------------------

# Datadog monitors
module "trigger_lambda_datadog_monitor" {
  source = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.15.2"

  service_name = local.trigger_lambda_name
  environment  = var.environment

  notification_endpoints            = "@slack-songwhip-alerts-dev"
  escalation_notification_endpoints = "@slack-songwhip-devs"
}

# ==============================================================================
# LAMBDA 2: MEDIACONVERT STATUS HANDLER
# ==============================================================================
#
# Purpose: Handles MediaConvert job completion and error notifications
#
# Trigger:  SNS notifications from MediaConvert jobs
# Actions:  - On SUCCESS: Tags source file with "transcoded=true" for Glacier
#           - On ERROR: Logs error and sends alerts to Sentry/Slack
#
# Resources:
#   - Sentry project for error tracking
#   - Lambda function (container-based, no VPC)
#   - IAM policies (S3 tagging)
#   - SNS subscription + Lambda permission
#   - Datadog monitors
#
# ==============================================================================

locals {
  status_lambda_name = "lambda-songwhip-mediaconvert-status"
}

# Sentry project for error tracking
module "status_lambda_sentry" {
  source = "git@github.com:theorchard/terraform-sentry//?ref=5.0.0"

  environment        = var.environment
  teams              = [var.environment]
  service_name       = local.status_lambda_name
  application_family = var.application_family
  platform           = "node"
}

# Lambda function configuration
module "status_lambda" {
  source = "git@github.com:theorchard/terraform-lambda.git//?ref=4.3.0"

  environment        = var.environment
  lambda_name        = local.status_lambda_name
  lambda_description = "Handles MediaConvert job status updates and errors"
  application_family = var.application_family

  # Container image for Lambda
  use_container_image = true
  vpc_enabled         = false

  # Function configuration
  lambda_function_timeout     = 60 # 1 minute
  lambda_function_memory_size = 512

  # Error handling
  dlq_enabled = true
  dlq_type    = "sns"

  # Monitoring
  datadog_enabled = true

  lambda_function_environment_variables = {
    SOURCE_BUCKET      = data.aws_s3_bucket.songwhip_content.id
    DESTINATION_BUCKET = data.aws_s3_bucket.songwhip_hls_content.id
    SENTRY_DSN         = module.status_lambda_sentry.sentry_key_dsn_public_output
    ENV                = var.environment
    PUBLIC_ENDPOINT    = var.songwhip_api_endpoint
  }
}

# ------------------------------------------------------------------------------
# IAM Policies for Status Lambda
# ------------------------------------------------------------------------------

# S3 tagging permission for Glacier transition
data "aws_iam_policy_document" "status_lambda_s3_tagging" {
  statement {
    effect = "Allow"

    actions = [
      "s3:PutObjectTagging",
      "s3:GetObjectTagging",
    ]

    resources = [
      "${data.aws_s3_bucket.songwhip_content.arn}/uploads/*",
    ]
  }
}

resource "aws_iam_policy" "status_lambda_s3_tagging" {
  name   = "S3-${var.environment}-songwhip-status-lambda-tagging"
  policy = data.aws_iam_policy_document.status_lambda_s3_tagging.json
}

resource "aws_iam_role_policy_attachment" "status_lambda_s3_tagging" {
  role       = module.status_lambda.lambda_role_id
  policy_arn = aws_iam_policy.status_lambda_s3_tagging.arn
}

# Secrets Manager access for webhook key
data "aws_iam_policy_document" "status_lambda_secrets_manager" {
  statement {
    effect = "Allow"

    actions = [
      "secretsmanager:GetSecretValue",
    ]

    resources = [
      "arn:aws:secretsmanager:us-east-1:619719722105:secret:qa/songwhip-api/SONGWHIP_WEBHOOK_KEY*",
    ]
  }
}

resource "aws_iam_policy" "status_lambda_secrets_manager" {
  name   = "SecretsManager-${var.environment}-songwhip-status-lambda"
  policy = data.aws_iam_policy_document.status_lambda_secrets_manager.json
}

resource "aws_iam_role_policy_attachment" "status_lambda_secrets_manager" {
  role       = module.status_lambda.lambda_role_id
  policy_arn = aws_iam_policy.status_lambda_secrets_manager.arn
}

# ------------------------------------------------------------------------------
# Monitoring for Status Lambda
# ------------------------------------------------------------------------------

# Datadog monitors
module "status_lambda_datadog_monitor" {
  source = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.15.2"

  service_name = local.status_lambda_name
  environment  = var.environment

  notification_endpoints            = "@slack-songwhip-alerts-dev"
  escalation_notification_endpoints = "@slack-songwhip-devs"
}
