resource "aws_s3_bucket" "input_bucket" {
  # checkov:skip=CKV_AWS_145:Using KMS encryption is recommended, but AES256 is also sufficient.
  bucket = "${var.environment}-${var.input_bucket_name}"
}

resource "aws_s3_bucket_acl" "input_bucket" {
  bucket = aws_s3_bucket.input_bucket.id
  acl    = "private"
}

resource "aws_s3_bucket_accelerate_configuration" "input_bucket" {
  bucket = aws_s3_bucket.input_bucket.id
  status = "Enabled"
}

resource "aws_s3_bucket_versioning" "input_bucket" {
  bucket = aws_s3_bucket.input_bucket.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_cors_configuration" "input_bucket" {
  count  = length(var.input_bucket_cors) == 0 ? 0 : 1
  bucket = aws_s3_bucket.input_bucket.id

  dynamic "cors_rule" {
    for_each = var.input_bucket_cors
    content {
      allowed_headers = cors_rule.value.allowed_headers
      allowed_methods = cors_rule.value.allowed_methods
      allowed_origins = cors_rule.value.allowed_origins
      expose_headers  = cors_rule.value.expose_headers
      max_age_seconds = cors_rule.value.max_age_seconds
    }
  }
}

resource "aws_s3_bucket_logging" "input_bucket" {
  for_each = toset(var.logging_target_bucket)

  bucket        = aws_s3_bucket.input_bucket.id
  target_bucket = each.value
  target_prefix = "${var.environment}-${var.input_bucket_name}"
}

resource "aws_s3_bucket_server_side_encryption_configuration" "input_bucket" {
  bucket = aws_s3_bucket.input_bucket.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

resource "aws_s3_bucket_public_access_block" "access_input_bucket" {
  bucket = aws_s3_bucket.input_bucket.id

  block_public_acls       = true
  block_public_policy     = true
  restrict_public_buckets = true
  ignore_public_acls      = true
}

resource "aws_s3_bucket_lifecycle_configuration" "input_bucket" {
  bucket = aws_s3_bucket.input_bucket.id

  rule {
    id     = "abort-incomplete-multipart-upload-days"
    status = "Enabled"
    abort_incomplete_multipart_upload {
      days_after_initiation = 7
    }
  }

  # Rule 2: Transition objects to S3 Glacier Deep Archive
  rule {
    id     = "transition-to-deep-archive"
    status = "Enabled"

    transition {
      days          = 180 
      storage_class = "DEEP_ARCHIVE"
    }
  }
}

locals {
  buckets = concat(var.output_buckets_names, var.preview_buckets_names)
}

data "aws_iam_policy_document" "output_buckets_readonly_policy" {
  statement {
    actions = [
      "s3:ListBucket",
    ]

    effect    = "Allow"
    resources = formatlist("arn:aws:s3:::%s", local.buckets)
  }

  statement {
    actions = [
      "s3:GetObject",
      "s3:HeadObject",
    ]

    effect    = "Allow"
    resources = formatlist("arn:aws:s3:::%s/*", local.buckets)
  }
}

resource "aws_iam_policy" "output_buckets_readonly_policy" {
  name        = "${var.environment}-asset-transcoder-output-buckets-readonly-policy"
  description = "Read only access to output buckets for asset-transcoder lambdas"
  policy      = data.aws_iam_policy_document.output_buckets_readonly_policy.json
}

data "aws_iam_policy_document" "output_buckets_readwrite_policy" {
  statement {
    actions = [
      "s3:ListBucket",
    ]

    effect    = "Allow"
    resources = formatlist("arn:aws:s3:::%s", local.buckets)
  }

  statement {
    actions = [
      "s3:GetObject",
      "s3:HeadObject",
      "s3:CopyObject",
      "s3:PutObject",
      "s3:PutObjectAcl",
      "s3:PutObjectTagging",
      "s3:PutObjectVersionAcl",
      "s3:PutObjectVersionTagging"
    ]

    effect    = "Allow"
    resources = formatlist("arn:aws:s3:::%s/*", local.buckets)
  }
}

resource "aws_iam_policy" "output_buckets_readwrite_policy" {
  name        = "${var.environment}-asset-transcoder-output-buckets-readwrite-policy"
  description = "Read / Write access to output buckets for asset-transcoder microservice"
  policy      = data.aws_iam_policy_document.output_buckets_readwrite_policy.json
}

data "aws_iam_policy_document" "input_bucket_policy" {
  statement {
    effect  = "Deny"
    actions = ["s3:PutObject"]
    not_resources = [
      "arn:aws:s3:::${aws_s3_bucket.input_bucket.id}/*.jpg",
      "arn:aws:s3:::${aws_s3_bucket.input_bucket.id}/*.jpeg",
      "arn:aws:s3:::${aws_s3_bucket.input_bucket.id}/*.tif",
      "arn:aws:s3:::${aws_s3_bucket.input_bucket.id}/*.tiff",
      "arn:aws:s3:::${aws_s3_bucket.input_bucket.id}/*.wav",
    ]
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }
  }
  statement {
    sid    = "DenyRequestsWithoutSSL"
    effect = "Deny"
    principals {
      type        = "*"
      identifiers = ["*"]
    }
    actions = ["s3:*"]
    resources = [
      aws_s3_bucket.input_bucket.arn,
      "${aws_s3_bucket.input_bucket.arn}/*",
    ]
    condition {
      test     = "Bool"
      variable = "aws:SecureTransport"
      values   = ["false"]
    }
  }
}

resource "aws_s3_bucket_policy" "input_bucket_write_policy" {
  policy = data.aws_iam_policy_document.input_bucket_policy.json
  bucket = aws_s3_bucket.input_bucket.id
}

data "aws_iam_policy_document" "input_bucket_readwrite_policy" {
  statement {
    actions = [
      "s3:ListBucket",
    ]

    effect    = "Allow"
    resources = [aws_s3_bucket.input_bucket.arn]
  }

  statement {
    actions = [
      "s3:GetObject",
      "s3:HeadObject",
      "s3:CopyObject",
      "s3:PutObject",
      "s3:PutObjectAcl",
      "s3:PutObjectTagging",
      "s3:PutObjectVersionAcl",
      "s3:PutObjectVersionTagging"
    ]

    effect = "Allow"
    resources = [
      "${aws_s3_bucket.input_bucket.arn}/*",
    ]
  }
}

resource "aws_iam_policy" "input_bucket_readwrite_policy" {
  name        = "${var.environment}-asset-transcoder-input-bucket-readwrite-policy"
  description = "Read / Write access to input buckets for asset-transcoder microservice"
  policy      = data.aws_iam_policy_document.input_bucket_readwrite_policy.json
}

data "aws_iam_policy_document" "input_bucket_readonly_policy" {
  statement {
    actions = [
      "s3:ListBucket",
    ]

    effect    = "Allow"
    resources = [aws_s3_bucket.input_bucket.arn]
  }

  statement {
    actions = [
      "s3:GetObject",
      "s3:HeadObject",
    ]

    effect    = "Allow"
    resources = [aws_s3_bucket.input_bucket.arn]
  }
}

resource "aws_iam_policy" "input_bucket_readonly_policy" {
  name        = "${var.environment}-asset-transcoder-input-bucket-readonly-policy"
  description = "Read only access to asset transcoder input bucket"
  policy      = data.aws_iam_policy_document.input_bucket_readonly_policy.json
}
