locals {
  config_replication = var.apply_replication_configuration
}

# Replication Source role.
resource "aws_iam_role" "s3_replication_role" {
  count                = length(local.config_replication) > 0 ? 1 : 0
  name                 = "S3-${local.bucket_name}-replication-role"
  assume_role_policy   = data.aws_iam_policy_document.s3_replication_assume_role_policy.json
  permissions_boundary = local.permissions_boundary_arn
}

# Replication Source AssumeRole policy document.
data "aws_iam_policy_document" "s3_replication_assume_role_policy" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["s3.amazonaws.com"]
    }
  }
}

# Replication Source policy document
data "aws_iam_policy_document" "s3_replication_policy" {
  statement {
    actions = [
      "s3:GetReplicationConfiguration",
      "s3:ListBucket"
    ]

    resources = [
      aws_s3_bucket.bucket.arn
    ]
  }

  statement {
    actions = [
      "s3:GetObjectVersion",
      "s3:GetObjectVersionAcl",
      "s3:GetObjectVersionForReplication",
      "s3:GetObjectVersionTagging"
    ]

    resources = [
      "${aws_s3_bucket.bucket.arn}/*"
    ]
  }

  dynamic "statement" {
    for_each = var.apply_replication_configuration
    content {
      actions = [
        "s3:ReplicateObject",
        "s3:ReplicateDelete",
        "s3:ReplicateTags",
      ]

      resources = [
        "arn:aws:s3:::${statement.value.destination_bucket}/*"
      ]
    }
  }

  # Grant KMS decrypt permissions if replication of KMS-encrypted objects is enabled
  dynamic "statement" {
    for_each = [for rule in var.apply_replication_configuration : rule if rule.replicate_kms_encrypted_objects]
    content {
      actions = [
        "kms:Decrypt",
        "kms:GenerateDataKey"
      ]

      condition {
        test     = "StringLike"
        values   = ["s3.${aws_s3_bucket.bucket.region}.amazonaws.com"]
        variable = "kms:ViaService"
      }

      condition {
        test = "StringLike"
        values = [
          aws_s3_bucket.bucket.arn,
          "${aws_s3_bucket.bucket.arn}/*"
        ]
        variable = "kms:EncryptionContext:aws:s3:arn"
      }

      # Include the default KMS encryption key if enabled, plus any additional keys specified in the rule
      resources = concat(var.kms_key_enabled ? [aws_kms_key.kms_key[0].arn] : [], statement.value.source_kms_key_arns)
    }
  }

  # Grant KMS encrypt permissions on the replica KMS key if replication of KMS-encrypted objects is enabled
  dynamic "statement" {
    for_each = [for rule in var.apply_replication_configuration : rule if rule.replicate_kms_encrypted_objects]

    content {
      actions = [
        "kms:Encrypt",
        "kms:GenerateDataKey"
      ]

      resources = [statement.value.replica_kms_key_arn]
    }
  }
}

# Replication Source policy
resource "aws_iam_policy" "s3_replication_policy" {
  count  = length(local.config_replication) > 0 ? 1 : 0
  name   = "S3-${local.bucket_name}-replication-policy"
  policy = data.aws_iam_policy_document.s3_replication_policy.json
}

# Replication Source policy attachment
resource "aws_iam_policy_attachment" "s3_replication_attachment" {
  count      = length(local.config_replication) > 0 ? 1 : 0
  name       = "S3-${local.bucket_name}-replication-policy-attachment"
  roles      = [aws_iam_role.s3_replication_role[0].name]
  policy_arn = aws_iam_policy.s3_replication_policy[0].arn
}

# Replication Source configuration
resource "aws_s3_bucket_replication_configuration" "replication" {
  count      = length(local.config_replication) > 0 ? 1 : 0
  depends_on = [aws_s3_bucket_versioning.versioning]
  bucket     = aws_s3_bucket.bucket.id
  role       = aws_iam_role.s3_replication_role[0].arn

  dynamic "rule" {
    for_each = local.config_replication

    content {
      id       = substr(replace("${rule.value["destination_bucket"]}-${rule.value["prefix"]}", "/", "_"), 0, 255)
      priority = rule.value["priority"]

      filter {
        prefix = rule.value["prefix"]
      }

      status = rule.value["enabled"] ? "Enabled" : "Disabled"

      delete_marker_replication {
        status = rule.value["delete_marker_replication_enabled"] ? "Enabled" : "Disabled"
      }

      dynamic "source_selection_criteria" {
        for_each = rule.value["replicate_kms_encrypted_objects"] ? [true] : []
        content {
          sse_kms_encrypted_objects {
            status = "Enabled"
          }
        }
      }

      destination {
        bucket        = "arn:aws:s3:::${rule.value["destination_bucket"]}"
        storage_class = rule.value["storage_class"]

        dynamic "encryption_configuration" {
          for_each = rule.value["replicate_kms_encrypted_objects"] ? [true] : []
          content {
            replica_kms_key_id = rule.value["replica_kms_key_arn"]
          }
        }

        metrics {
          status = rule.value["metrics_enabled"] ? "Enabled" : "Disabled"
          dynamic "event_threshold" {
            for_each = rule.value["replication_time_control_enabled"] ? [true] : []
            content {
              minutes = 15
            }
          }
        }

        replication_time {
          status = rule.value["replication_time_control_enabled"] ? "Enabled" : "Disabled"
          time {
            minutes = 15
          }
        }
      }
    }
  }
}
