# Scheduled Product Metadata Update Step Function.
# know which account you're in
data "aws_caller_identity" "current" {}

module "default_tags" {
  source             = "git@github.com:theorchard/terraform-default-tags.git//?ref=1.0.0"
  environment        = var.environment
  application_family = var.application_family
  service_name       = var.state_machine_name
}

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = module.default_tags.tags
  }
}

terraform {
  backend "s3" {
    bucket  = "orcd-terraform-state"
    key     = "qa/sfn-scheduled-product-metadata-update/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

data "aws_lambda_function" "update_product_values_lambda" {
  function_name = "${var.environment}-lambda-timed-release-update-product-values"
}

data "aws_lambda_function" "update_metadata_queue_lambda" {
  function_name = "${var.environment}-lambda-timed-release-update-metadata-queue"
}

data "aws_lambda_function" "process_metadata_queue_lambda" {
  function_name = "${var.environment}-lambda-timed-release-process-metadata-queue"
}

data "aws_lambda_function" "notify_label_manager_lambda" {
  function_name = "${var.environment}-lambda-timed-release-notify-label-manager"
}

# Assume role policy for state machine.
data "aws_iam_policy_document" "assume_role_for_scheduled_product_metadata_policy" {
  statement {
    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type = "Service"

      identifiers = [
        "states.${var.aws_region}.amazonaws.com",
      ]
    }
  }
}

# States role for lambda invocation.
resource "aws_iam_role" "role_for_state_machine" {
  name               = "${var.environment}-scheduled-product-metadata-update-lambdas-role"
  assume_role_policy = data.aws_iam_policy_document.assume_role_for_scheduled_product_metadata_policy.json
}

# Policy that gives the state machine role permission to invoke lambdas! Hopefully!
data "aws_iam_policy_document" "invoke_schedule_product_update_lambdas_policy_document" {
  statement {
    actions = [
      "lambda:InvokeFunction"
    ]

    resources = [
      data.aws_lambda_function.update_product_values_lambda.arn,
      data.aws_lambda_function.update_metadata_queue_lambda.arn,
      data.aws_lambda_function.process_metadata_queue_lambda.arn,
      data.aws_lambda_function.notify_label_manager_lambda.arn,
    ]
  }
}

# Policy document that lets other things invoke this sfn
data "aws_iam_policy_document" "invoke_sfn_policy_document" {
  statement {
    effect = "Allow"
    actions = [
      "states:StartExecution",
      "states:ListExecutions"
    ]

    resources = [
      aws_sfn_state_machine.sfn_scheduled_product_metadata_update.arn
    ]
  }
}

# Policy that uses the policy document
resource "aws_iam_policy" "invoke_sfn_policy" {
  name        = "StepFunctions-${var.environment}-${var.state_machine_name}-StartExecution"
  policy      = data.aws_iam_policy_document.invoke_sfn_policy_document.json
  description = "Policy that allows invoking the scheduled product metadata update sfn."
}

# Policy that gives the state machine role permission to invoke lambdas
resource "aws_iam_role_policy" "sfn_scheduled_product_metadata_update_invoke_lambda_role_policy" {
  name   = "${var.environment}-sfn-scheduled-product-metadata-update-invoke-lambda-role-policy"
  role   = aws_iam_role.role_for_state_machine.id
  policy = data.aws_iam_policy_document.invoke_schedule_product_update_lambdas_policy_document.json
}

# Step Function cloudwatch logs permission policy
data "aws_iam_policy_document" "cloudwatch_log_event_policy_document" {
  statement {
    effect = "Allow"
    resources = [
      "${aws_cloudwatch_log_group.sfn_log_group.arn}:*",
    ]

    actions = [
      "logs:CreateLogStream",
      "logs:PutLogEvents",
    ]
  }

  statement {
    effect    = "Allow"
    resources = ["*"]
    actions = [
      "logs:CreateLogDelivery",
      "logs:DeleteLogDelivery",
      "logs:DescribeLogGroups",
      "logs:DescribeResourcePolicies",
      "logs:GetLogDelivery",
      "logs:ListLogDeliveries",
      "logs:PutResourcePolicy",
      "logs:UpdateLogDelivery",
    ]
  }
}


data "aws_lambda_function" "datadog_lambda_function" {
  function_name = "DatadogLambdaFunction"
}

resource "aws_iam_policy" "sfn_log_event_policy" {
  name        = "${var.environment}-${var.state_machine_name}-log-policy"
  description = "${var.environment}-${var.state_machine_name}-log-policy"
  policy      = data.aws_iam_policy_document.cloudwatch_log_event_policy_document.json
}

resource "aws_iam_role_policy_attachment" "sfn_log_event_policy_attachment" {
  role       = aws_iam_role.role_for_state_machine.name
  policy_arn = aws_iam_policy.sfn_log_event_policy.arn
}

resource "aws_cloudwatch_log_group" "sfn_log_group" {
  name              = "${var.environment}-${var.state_machine_name}-log-group"
  retention_in_days = 365
  tags = {
    application_family = var.application_family
    environment        = var.environment
    service_name       = var.state_machine_name
    terraformed        = true
  }
}

resource "aws_cloudwatch_log_subscription_filter" "datadog_lambda_log_filter" {
  name            = "${var.environment}-${var.state_machine_name}-log-group-subscription-filter"
  log_group_name  = aws_cloudwatch_log_group.sfn_log_group.name
  filter_pattern  = ""
  destination_arn = data.aws_lambda_function.datadog_lambda_function.arn
  distribution    = "ByLogStream"
}

# Step Function (SFN) machine definition template
data "template_file" "state_machine_definition" {
  template = file("${path.module}/stepfunction.json")
  # add all lambda variables here.
  vars = {
    lambda_update_product_values_arn = data.aws_lambda_function.update_product_values_lambda.arn
    lambda_update_metadata_queue_arn = data.aws_lambda_function.update_metadata_queue_lambda.arn
    lambda_process_metadata_queue_arn = data.aws_lambda_function.process_metadata_queue_lambda.arn
    lambda_notify_label_manager_arn = data.aws_lambda_function.notify_label_manager_lambda.arn
  }
}

resource "aws_sfn_state_machine" "sfn_scheduled_product_metadata_update" {
  name       = "${var.environment}-${var.state_machine_name}"
  role_arn   = aws_iam_role.role_for_state_machine.arn
  definition = data.template_file.state_machine_definition.rendered

  tags = {
    application_family = var.application_family
    environment        = var.environment
    service_name       = var.state_machine_name
    terraformed        = true
  }

  logging_configuration {
    log_destination        = "${aws_cloudwatch_log_group.sfn_log_group.arn}:*"
    include_execution_data = true
    level                  = "ERROR"
  }

  tracing_configuration {
    enabled = true
  }
}

# Datadog Dashboard
module "datadog_sfn_dashboard" {
  source             = "git@github.com:theorchard/terraform-datadog.git//modules/step-function?ref=6.13.4"
  environment        = var.environment
  service_name       = var.state_machine_name
  application_family = var.application_family
  statemachine_arn   = aws_sfn_state_machine.sfn_scheduled_product_metadata_update.arn

  # failed log monitor
  failed_execution_message_log_monitor = {
    enabled        = true
    log_group_name = aws_cloudwatch_log_group.sfn_log_group.name
  }

  notification_endpoints            = var.notification_endpoints
  escalation_notification_endpoints = var.escalation_notification_endpoints
}

resource "datadog_monitor" "statemachine_failed_log_monitor" {
  count              = 1
  name               = "${var.environment}-${var.state_machine_name} notify-label-manager step failed log monitor on {{log.attributes.host}}"
  type               = "log alert"
  message            = "{{#is_alert}}\nNotify Label Manager step failed with cause:\n\n```\n{{{log.attributes.[details.cause]}}}\n```\n\n\nNotify: ${var.escalation_notification_endpoints} \n{{/is_alert}}"

  query = "logs(\"source:cloudwatch @aws.awslogs.logGroup:${aws_cloudwatch_log_group.sfn_log_group.name}* @type:ExecutionFailed @details.error:NotifyLabelManagerFailed\").index(\"*\").rollup(\"count\").last(\"1m\") >= 1"

  monitor_thresholds {
    critical = 1
  }

  include_tags        = true
  notify_no_data      = false
  notify_audit        = false
  timeout_h           = 0
  require_full_window = false
}
