locals {
  lambda_function_names = [for name in var.lambda_names : "${var.environment}-${var.service_name}-${name}"]
}

# Assume role policy used by Jenkins pipeline agent role
data "aws_iam_policy_document" "integration_tests_assume_role_policy" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type = "AWS"

      identifiers = [
        "arn:aws:iam::437795906767:role/prod-jenkins-aws-pipeline-agent",
      ]
    }
  }
}

# Jenkins agents will assume this role in order to access AWS resources
resource "aws_iam_role" "integration_tests_role" {
  name               = "${var.environment}-${var.service_name}-integration-tests-role"
  assume_role_policy = data.aws_iam_policy_document.integration_tests_assume_role_policy.json
}

data "aws_iam_policy_document" "lambda_invoke_policy_document" {
  statement {
    effect  = "Allow"
    actions = ["lambda:InvokeFunction"]

    resources = [
      for fn in local.lambda_function_names :
      "arn:aws:lambda:${var.aws_region}:${data.aws_caller_identity.current.account_id}:function:${fn}"
    ]
  }
}

resource "aws_iam_policy" "lambda_invoke_policy" {
  name   = "Lambda-${var.environment}-${var.service_name}-integration-tests-policy"
  policy = data.aws_iam_policy_document.lambda_invoke_policy_document.json
}

resource "aws_iam_role_policy_attachment" "lambda_invoke_policy_attachment" {
  role       = aws_iam_role.integration_tests_role.name
  policy_arn = aws_iam_policy.lambda_invoke_policy.arn
}

# Secrets Manager read access for e2e test credentials
data "aws_iam_policy_document" "secrets_manager_policy_document" {
  statement {
    effect = "Allow"

    actions = [
      "secretsmanager:GetResourcePolicy",
      "secretsmanager:GetSecretValue",
      "secretsmanager:DescribeSecret",
      "secretsmanager:ListSecretVersionIds",
    ]

    resources = [
      "arn:aws:secretsmanager:${var.aws_region}:${data.aws_caller_identity.current.account_id}:secret:qa/e2e-test-secrets/neo4j/suite-username*",
      "arn:aws:secretsmanager:${var.aws_region}:${data.aws_caller_identity.current.account_id}:secret:qa/e2e-test-secrets/neo4j/suite-password*",
      "arn:aws:secretsmanager:${var.aws_region}:${data.aws_caller_identity.current.account_id}:secret:qa/e2e-test-secrets/neo4j/suite-hostname*",
      "arn:aws:secretsmanager:${var.aws_region}:${data.aws_caller_identity.current.account_id}:secret:qa/e2e-test-secrets/db/art-relations*",
      "arn:aws:secretsmanager:${var.aws_region}:${data.aws_caller_identity.current.account_id}:secret:qa/e2e-test-secrets/db/royalty-accounting*",
      "arn:aws:secretsmanager:${var.aws_region}:${data.aws_caller_identity.current.account_id}:secret:qa/e2e-test-secrets/db/SNOWFLAKE_KEY*",
    ]
  }
}

resource "aws_iam_policy" "secrets_manager_policy" {
  name   = "SecretsManager-${var.environment}-${var.service_name}-integration-tests-policy"
  policy = data.aws_iam_policy_document.secrets_manager_policy_document.json
}

resource "aws_iam_role_policy_attachment" "secrets_manager_policy_attachment" {
  role       = aws_iam_role.integration_tests_role.name
  policy_arn = aws_iam_policy.secrets_manager_policy.arn
}

# Step Functions access to start and monitor the product-transfer state machine
data "aws_iam_policy_document" "sfn_policy_document" {
  statement {
    effect  = "Allow"
    actions = ["states:StartExecution"]

    resources = [
      "arn:aws:states:${var.aws_region}:${data.aws_caller_identity.current.account_id}:stateMachine:${var.environment}-${var.sfn_name}",
    ]
  }

  statement {
    effect    = "Allow"
    actions   = ["states:ListStateMachines"]
    resources = ["*"]
  }

  statement {
    effect    = "Allow"
    actions   = ["states:ListExecutions"]

    resources = [
      "arn:aws:states:${var.aws_region}:${data.aws_caller_identity.current.account_id}:stateMachine:${var.environment}-${var.sfn_name}",
    ]
  }

  statement {
    effect = "Allow"

    actions = [
      "states:DescribeExecution",
      "states:GetExecutionHistory",
      "states:StopExecution",
    ]

    resources = [
      "arn:aws:states:${var.aws_region}:${data.aws_caller_identity.current.account_id}:execution:${var.environment}-${var.sfn_name}:*",
    ]
  }
}

resource "aws_iam_policy" "sfn_policy" {
  name   = "StepFunctions-${var.environment}-${var.service_name}-integration-tests-policy"
  policy = data.aws_iam_policy_document.sfn_policy_document.json
}

resource "aws_iam_role_policy_attachment" "sfn_policy_attachment" {
  role       = aws_iam_role.integration_tests_role.name
  policy_arn = aws_iam_policy.sfn_policy.arn
}

# Per-lambda roles for local RIE integration tests
resource "aws_iam_role" "lambda_integration_tests_role" {
  for_each           = toset(var.lambda_names)
  name               = "${var.environment}-lambda-pt-${each.key}-integration-tests-role"
  assume_role_policy = data.aws_iam_policy_document.integration_tests_assume_role_policy.json
}

data "aws_iam_policy_document" "lambda_rie_invoke_policy_document" {
  for_each = toset(var.lambda_names)

  statement {
    effect  = "Allow"
    actions = ["lambda:InvokeFunction"]

    resources = [
      "arn:aws:lambda:${var.aws_region}:${data.aws_caller_identity.current.account_id}:function:${var.environment}-${var.service_name}-${each.key}",
    ]
  }
}

resource "aws_iam_policy" "lambda_integration_tests_invoke_policy" {
  for_each = toset(var.lambda_names)
  name     = "Lambda-${var.environment}-${var.service_name}-${each.key}-integration-tests-policy"
  policy   = data.aws_iam_policy_document.lambda_rie_invoke_policy_document[each.key].json
}

resource "aws_iam_role_policy_attachment" "lambda_integration_tests_invoke_attachment" {
  for_each   = toset(var.lambda_names)
  role       = aws_iam_role.lambda_integration_tests_role[each.key].name
  policy_arn = aws_iam_policy.lambda_integration_tests_invoke_policy[each.key].arn
}

data "aws_iam_policy_document" "lambda_runtime_secrets_policy_document" {
  for_each = toset(var.lambda_names)

  statement {
    effect = "Allow"

    actions = [
      "secretsmanager:GetResourcePolicy",
      "secretsmanager:GetSecretValue",
      "secretsmanager:DescribeSecret",
      "secretsmanager:ListSecretVersionIds",
    ]

    resources = [
      "arn:aws:secretsmanager:${var.aws_region}:${data.aws_caller_identity.current.account_id}:secret:${var.environment}/${var.service_name}-${each.key}/*",
    ]
  }
}

resource "aws_iam_policy" "lambda_runtime_secrets_policy" {
  for_each = toset(var.lambda_names)
  name     = "LambdaSecrets-${var.environment}-${var.service_name}-${each.key}-integration-tests-policy"
  policy   = data.aws_iam_policy_document.lambda_runtime_secrets_policy_document[each.key].json
}

resource "aws_iam_role_policy_attachment" "lambda_runtime_secrets_attachment" {
  for_each   = toset(var.lambda_names)
  role       = aws_iam_role.lambda_integration_tests_role[each.key].name
  policy_arn = aws_iam_policy.lambda_runtime_secrets_policy[each.key].arn
}

# Reuse existing test fixture secrets policy
resource "aws_iam_role_policy_attachment" "lambda_integration_tests_fixture_secrets_attachment" {
  for_each   = toset(var.lambda_names)
  role       = aws_iam_role.lambda_integration_tests_role[each.key].name
  policy_arn = aws_iam_policy.secrets_manager_policy.arn
}
