terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>4.0"
    }
  }
}

provider "aws" {
  region  = var.region
  profile = var.aws_profile_name

}

locals {
  project_name = "stepfunctions-sampleproject"

}

data "aws_caller_identity" "caller" {}
data "aws_partition" "partition" {}

#Create the Event Bus
resource "aws_cloudwatch_event_bus" "bus" {
  name = "${local.project_name}-eventbus"
}

#Create the Event Bridge Rule
resource "aws_cloudwatch_event_rule" "rule" {
  name           = "${local.project_name}-rule"
  description    = "Step Function Test Rule"
  event_pattern  = <<EOL
    {"source":["my.statemachine"],"detail-type":["MessageFromStepFunctions"]}
EOL
  event_bus_name = aws_cloudwatch_event_bus.bus.name
}

#Add Lambda target to bus
resource "aws_cloudwatch_event_target" "lambda_target" {
  rule           = aws_cloudwatch_event_rule.rule.name
  arn            = aws_lambda_function.sfn_lambda.arn
  event_bus_name = aws_cloudwatch_event_bus.bus.name
}

# Add SQS target to bus
resource "aws_cloudwatch_event_target" "sqs_target" {
  rule           = aws_cloudwatch_event_rule.rule.name
  arn            = aws_sqs_queue.queue.arn
  event_bus_name = aws_cloudwatch_event_bus.bus.name
}

# Add SNS Target to bus
resource "aws_cloudwatch_event_target" "sns_target" {
  rule           = aws_cloudwatch_event_rule.rule.name
  arn            = aws_sns_topic.topic.arn
  event_bus_name = aws_cloudwatch_event_bus.bus.name
}

## Create the State Machine

resource "aws_sfn_state_machine" "state_machine" {
  name       = "${local.project_name}-sfn"
  type       = "STANDARD"
  definition = file("statemachine/statemachine.asl.json")
  role_arn   = aws_iam_role.sfn_role.arn

}

#Step Function Role
resource "aws_iam_role" "sfn_role" {
  name = "${local.project_name}-sfn-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          Service = "states.amazonaws.com"
        }
      },
    ]
  })
  inline_policy {
    name = "allow_put_eb"
    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
      "Sid": "Stmt1665517897412",
      "Action": [
        "events:PutEvents"
      ],
      "Effect": "Allow",
      "Resource": "${aws_cloudwatch_event_bus.bus.arn}"
    }
      ]
    })
  }
}

#Create the lambda trust policy
resource "aws_iam_role" "lambda_role" {
  name               = "${local.project_name}-lambda-role"
  assume_role_policy = <<EOF
    {
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
inline_policy {
  name = "default_policy"
  policy =jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
      "Sid": "putcW",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Effect": "Allow",
      "Resource": "arn:${data.aws_partition.partition.partition}:logs:${var.region}:${data.aws_caller_identity.caller.account_id}:*"
    }
    ]


})

}
}

#Zip up the function for deployment
data "archive_file" "func" {
  type        = "zip"
  source_file = "src/handler.py"
  output_path = "${path.module}/files/func.zip"
}

#Create the CloudWatch Logs log group with 1 day retention
resource "aws_cloudwatch_log_group" "log_group" {
  name = "/aws/lambda/${local.project_name}-function"
  retention_in_days = 1
}

#Create the lambda function target
resource "aws_lambda_function" "sfn_lambda" {
  function_name = "${local.project_name}-function"
  role          = aws_iam_role.lambda_role.arn
  filename      = "${path.module}/files/func.zip"
  handler       = "handler.handler"
  source_code_hash = data.archive_file.func.output_base64sha256
  runtime          = "python3.9"
}

#Lambda Permission for EB invocation
resource "aws_lambda_permission" "allow_eb" {
  statement_id  = "AllowEBInvoke"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.sfn_lambda.function_name
  principal     = "events.amazonaws.com"
  source_arn    = aws_cloudwatch_event_rule.rule.arn

}

# Create the SQS target queue
resource "aws_sqs_queue" "queue" {
  name = "${local.project_name}-queue"
}

# SQS Queue Policy allowing EB to publish events. 
resource "aws_sqs_queue_policy" "queue_policy" {
  queue_url = aws_sqs_queue.queue.id
  policy    = data.aws_iam_policy_document.sqs_policy_doc.json
}

#SNS Topic
resource "aws_sns_topic" "topic" {
  name = "${local.project_name}-topic"

}
# Create the SNS publishing policy 
resource "aws_sns_topic_policy" "topic_policy" {
  arn    = aws_sns_topic.topic.arn
  policy = data.aws_iam_policy_document.sns_policy_doc.json
}

#SNS publishing policy document
data "aws_iam_policy_document" "sns_policy_doc" {
  policy_id = "__default"
  statement {
    actions = [
      "SNS:Publish"
    ]
    condition {
      test     = "ArnEquals"
      variable = "aws:SourceArn"
      values   = [aws_cloudwatch_event_rule.rule.arn]
    }
    principals {
      type        = "Service"
      identifiers = ["events.amazonaws.com"]
    }
    resources = [
      aws_sns_topic.topic.arn
    ]
  }

}
# SQS Publishing policy document
data "aws_iam_policy_document" "sqs_policy_doc" {
  policy_id = "__default"
  statement {
    actions = [
      "SQS:SendMessage"
    ]
    condition {
      test     = "ArnEquals"
      variable = "aws:SourceArn"
      values   = [aws_cloudwatch_event_rule.rule.arn]
    }
    principals {
      type        = "Service"
      identifiers = ["events.amazonaws.com"]
    }
    resources = [
      aws_sqs_queue.queue.arn
    ]
  }
}