resource "aws_s3_bucket" "metering" {
  count = local.premium_metering_enabled ? 1 : 0

  bucket        = local.metering_bucket_name
  force_destroy = true

  tags = merge(local.common_tags, {
    Name = local.metering_bucket_name
  })
}

resource "aws_s3_bucket_ownership_controls" "metering" {
  count = local.premium_metering_enabled ? 1 : 0

  bucket = aws_s3_bucket.metering[0].id

  rule {
    object_ownership = "BucketOwnerEnforced"
  }
}

resource "aws_s3_bucket_public_access_block" "metering" {
  count = local.premium_metering_enabled ? 1 : 0

  bucket                  = aws_s3_bucket.metering[0].id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_server_side_encryption_configuration" "metering" {
  count = local.premium_metering_enabled ? 1 : 0

  bucket = aws_s3_bucket.metering[0].id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

data "aws_iam_policy_document" "metering_writer_assume" {
  count = local.premium_metering_enabled ? 1 : 0

  statement {
    sid     = "TrustedDataplaneAccounts"
    effect  = "Allow"
    actions = ["sts:AssumeRole"]

    principals {
      type = "AWS"
      identifiers = [
        for account in local.dataplane_accounts : "arn:aws:iam::${account}:root"
      ]
    }
  }
}

data "aws_iam_policy_document" "metering_writer" {
  count = local.premium_metering_enabled ? 1 : 0

  statement {
    sid    = "MeteringBucketRead"
    effect = "Allow"
    actions = [
      "s3:GetBucketLocation",
      "s3:ListBucket",
      "s3:ListBucketMultipartUploads",
    ]
    resources = [aws_s3_bucket.metering[0].arn]
  }

  # The metering SDK calls HeadObject before PutObject to avoid overwriting an
  # existing minute. S3 authorizes HeadObject through GetObject, so the
  # production role named "write-only" is intentionally a writer contract,
  # not a strict no-read contract.
  statement {
    sid    = "MeteringObjectWrite"
    effect = "Allow"
    actions = [
      "s3:AbortMultipartUpload",
      "s3:GetObject",
      "s3:ListMultipartUploadParts",
      "s3:PutObject",
    ]
    resources = ["${aws_s3_bucket.metering[0].arn}/*"]
  }
}

resource "aws_iam_role" "metering_writer" {
  count = local.premium_metering_enabled ? 1 : 0

  name                 = local.metering_writer_role_name
  description          = "cp9 ${local.session_name} Premium dataplane metering writer"
  assume_role_policy   = data.aws_iam_policy_document.metering_writer_assume[0].json
  permissions_boundary = local.developer_boundary_policy_arn

  tags = merge(local.common_tags, {
    Name = local.metering_writer_role_name
  })
}

resource "aws_iam_role_policy" "metering_writer" {
  count = local.premium_metering_enabled ? 1 : 0

  name   = local.metering_writer_role_name
  role   = aws_iam_role.metering_writer[0].id
  policy = data.aws_iam_policy_document.metering_writer[0].json
}

data "aws_iam_policy_document" "metering_read_write_assume" {
  count = local.premium_metering_enabled ? 1 : 0

  statement {
    sid     = "TrustedCp9DeveloperSession"
    effect  = "Allow"
    actions = ["sts:AssumeRole"]

    principals {
      type        = "AWS"
      identifiers = [local.developer_role_arn]
    }

    condition {
      test     = "StringEquals"
      variable = "aws:PrincipalTag/cp9-owner"
      values   = [local.owner]
    }

    condition {
      test     = "StringEquals"
      variable = "aws:PrincipalTag/cp9-session"
      values   = [local.session_name]
    }
  }

  statement {
    sid     = "TrustedSessionRuntimes"
    effect  = "Allow"
    actions = ["sts:AssumeRole"]

    principals {
      type = "AWS"
      identifiers = concat(
        [aws_iam_role.dataplane_manager[0].arn],
        local.remote_ec2_k3d_enabled ? [aws_iam_role.remote_runtime[0].arn] : [],
      )
    }
  }
}

data "aws_iam_policy_document" "metering_read_write" {
  count = local.premium_metering_enabled ? 1 : 0

  statement {
    sid    = "MeteringBucketRead"
    effect = "Allow"
    actions = [
      "s3:GetBucketLocation",
      "s3:ListBucket",
      "s3:ListBucketMultipartUploads",
    ]
    resources = [aws_s3_bucket.metering[0].arn]
  }

  statement {
    sid    = "MeteringObjectReadWrite"
    effect = "Allow"
    actions = [
      "s3:AbortMultipartUpload",
      "s3:DeleteObject",
      "s3:GetObject",
      "s3:ListMultipartUploadParts",
      "s3:PutObject",
    ]
    resources = ["${aws_s3_bucket.metering[0].arn}/*"]
  }
}

resource "aws_iam_role" "metering_read_write" {
  count = local.premium_metering_enabled ? 1 : 0

  name                 = local.metering_read_write_role_name
  description          = "cp9 ${local.session_name} Premium metering reader and control-plane writer"
  assume_role_policy   = data.aws_iam_policy_document.metering_read_write_assume[0].json
  permissions_boundary = local.developer_boundary_policy_arn

  tags = merge(local.common_tags, {
    Name = local.metering_read_write_role_name
  })
}

resource "aws_iam_role_policy" "metering_read_write" {
  count = local.premium_metering_enabled ? 1 : 0

  name   = local.metering_read_write_role_name
  role   = aws_iam_role.metering_read_write[0].id
  policy = data.aws_iam_policy_document.metering_read_write[0].json
}
