# Create a lambda function for dd-search
resource "aws_lambda_function" "dd_search_lambda_function" {
  filename                       = "${path.module}/lambda.zip"
  runtime                        = "python3.6"
  function_name                  = "${var.env}-${var.lambda_name}"
  role                           = aws_iam_role.lambda_function_role.arn
  handler                        = var.lambda_function_handler
  timeout                        = var.lambda_function_timeout
  memory_size                    = var.lambda_function_memory_size
  reserved_concurrent_executions = var.lambda_function_concurrent_executions

  vpc_config {
    subnet_ids         = var.vpc_subnet_ids
    security_group_ids = var.vpc_security_group_ids
  }

  environment {
    variables = var.lambda_function_environment_variables
  }

  tags = {
    terraformed = "true"
  }
}

# Create an SNS topic to send notifications on invocation errors
resource "aws_sns_topic" "sns_error_topic" {
  name = "${var.env}-${var.lambda_name}-errors"
}

# Create the cloudwatch metric alarm
resource "aws_cloudwatch_metric_alarm" "dd_search_cloudwatch_alert" {
  alarm_name          = "${var.env}-${var.lambda_name}-error-alarm"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = 1
  datapoints_to_alarm = 1
  metric_name         = "Errors"
  period              = 60
  namespace           = "AWS/Lambda"
  threshold           = 1
  statistic           = "Sum"
  alarm_actions       = [aws_sns_topic.sns_error_topic.arn]
  dimensions = {
    FunctionName = "${var.env}-${var.lambda_name}"
  }
}

# Assume role policy for access to lambda
data "aws_iam_policy_document" "assume_lambda_role" {
  statement {
    actions = ["sts:AssumeRole"]

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

# Create IAM role for lambda function and attach the assume role policy
resource "aws_iam_role" "lambda_function_role" {
  name               = "${var.env}-${var.lambda_name}-lambda-role"
  assume_role_policy = data.aws_iam_policy_document.assume_lambda_role.json
}

# Lambda vpc execution policy data resource
data "aws_iam_policy_document" "lambda_vpc_execution_policy" {
  statement {
    effect = "Allow"

    actions = [
      "ec2:CreateNetworkInterface",
      "ec2:DescribeNetworkInterfaces",
      "ec2:DeleteNetworkInterface",
      "logs:CreateLogGroup",
      "logs:CreateLogStream",
      "logs:PutLogEvents",
    ]

    resources = [
      "*",
    ]
  }
}

# SNS policy data resource
data "aws_iam_policy_document" "sns_send_message" {
  statement {
    effect = "Allow"

    actions = [
      "sns:SendMessage",
      "sns:Publish",
    ]

    resources = [
      aws_sns_topic.sns_error_topic.arn,
    ]
  }
}

# Kinesis policy data resource
data "aws_iam_policy_document" "kinesis_stream_read_policy" {
  statement {
    effect = "Allow"

    actions = [
      "kinesis:ListStreams",
    ]

    resources = [
      "*",
    ]
  }

  statement {
    effect = "Allow"

    actions = [
      "kinesis:DescribeStream",
      "kinesis:GetRecords",
      "kinesis:GetShardIterator",
    ]

    resources = [
      var.kinesis_stream_name,
    ]
  }
}

# Create lambda basic execution policy
resource "aws_iam_policy" "lambda_vpc_execution_policy" {
  name   = "${var.env}-${var.lambda_name}-lambda_vpc_execution"
  policy = data.aws_iam_policy_document.lambda_vpc_execution_policy.json
}

# Create SNS policy
resource "aws_iam_policy" "sns_send_message" {
  name   = "SNS-${var.env}-${var.lambda_name}-SendMessage-Publish"
  policy = data.aws_iam_policy_document.sns_send_message.json
}

# Create Kinesis policy
resource "aws_iam_policy" "kinesis_stream_read_policy" {
  name   = "Kinesis-${var.env}-${var.lambda_name}-RO"
  policy = data.aws_iam_policy_document.kinesis_stream_read_policy.json
}

# Attach lambda basic execution policy to the lambda role
resource "aws_iam_role_policy_attachment" "lambda_vpc_execution_policy" {
  role       = aws_iam_role.lambda_function_role.name
  policy_arn = aws_iam_policy.lambda_vpc_execution_policy.arn
}

# Attach SNS policy to the lambda role
resource "aws_iam_role_policy_attachment" "sns_send_message" {
  role       = aws_iam_role.lambda_function_role.name
  policy_arn = aws_iam_policy.sns_send_message.arn
}

# Attach Kinesis trigger execution policy
resource "aws_iam_role_policy_attachment" "kinesis_stream_read_policy" {
  role       = aws_iam_role.lambda_function_role.name
  policy_arn = aws_iam_policy.kinesis_stream_read_policy.arn
}

# Set the kinesis trigger on the lambda function
resource "aws_lambda_event_source_mapping" "kinesis_trigger" {
  batch_size        = var.kinesis_batch_size
  event_source_arn  = var.kinesis_stream_name
  enabled           = true
  function_name     = aws_lambda_function.dd_search_lambda_function.arn
  starting_position = "TRIM_HORIZON"
}

