#############################################
# Use Managed Caching and Forwarding Policies
#############################################
data "aws_cloudfront_cache_policy" "caching_disabled" {
  name = "Managed-CachingDisabled"
}

data "aws_cloudfront_origin_request_policy" "all_viewer_except_host_header" {
  name = "Managed-AllViewerExceptHostHeader"
}

############################################
# CloudFront Distribution
############################################

resource "aws_cloudfront_distribution" "this" {

  ##########################################
  # Origins
  ##########################################

  dynamic "origin" {
    for_each = { for o in var.origins : o.origin_id => o }

    content {
      domain_name = origin.value.origin_domain_name
      origin_id   = origin.value.origin_id

      ######################################
      # S3 Origin
      ######################################
      dynamic "s3_origin_config" {
        for_each = origin.value.origin_type == "s3" ? [1] : []

        content {
          origin_access_identity = aws_cloudfront_origin_access_identity.oai[origin.key].cloudfront_access_identity_path
        }
      }

      ######################################
      # API Gateway Origin
      ######################################
      dynamic "custom_origin_config" {
        for_each = origin.value.origin_type == "api" ? [1] : []

        content {
          http_port              = 80
          https_port             = 443
          origin_protocol_policy = "https-only"
          origin_ssl_protocols   = ["TLSv1.2"]
        }
      }
    }
  }

  enabled = true
  aliases = var.aliases

  ##########################################
  # Default Cache Behavior (S3)
  ##########################################

  default_cache_behavior {
    target_origin_id = "s3-origin"

    viewer_protocol_policy = "redirect-to-https"

    allowed_methods = ["GET", "HEAD"]
    cached_methods  = ["GET", "HEAD"]

    forwarded_values {
      query_string = false

      cookies {
        forward = "none"
      }
    }

    compress     = true
    min_ttl      = 0
    default_ttl  = 3600
    max_ttl      = 86400
  }

  ##########################################
  # API Behavior
  ##########################################

  ordered_cache_behavior {
    path_pattern     = "/v1/*"
    target_origin_id = "api-origin"

    viewer_protocol_policy = "redirect-to-https"

    allowed_methods = ["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"]
    cached_methods  = ["GET","HEAD"]

    cache_policy_id          = data.aws_cloudfront_cache_policy.caching_disabled.id
    origin_request_policy_id = data.aws_cloudfront_origin_request_policy.all_viewer_except_host_header.id
  }

  price_class = "PriceClass_All"

  ##########################################
  # Geo Restrictions
  ##########################################

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  ##########################################
  # SSL Certificate
  ##########################################

  viewer_certificate {
    acm_certificate_arn      = var.acm_certificate_arn
    ssl_support_method       = var.acm_certificate_arn != null ? "sni-only" : null
    minimum_protocol_version = var.acm_certificate_arn != null ? "TLSv1.2_2021" : null

    cloudfront_default_certificate = var.acm_certificate_arn == null
  }
}

############################################
# Origin Access Identities (S3 only)
############################################

resource "aws_cloudfront_origin_access_identity" "oai" {
  for_each = {
    for o in var.origins : o.origin_id => o
    if o.origin_type == "s3"
  }

  comment = "OAI for ${each.key}"
}

############################################
# S3 Bucket Policy (S3 only)
############################################

resource "aws_s3_bucket_policy" "bucket_policy" {
  for_each = {
    for o in var.origins : o.origin_id => o
    if o.origin_type == "s3"
  }

  bucket = each.value.bucket_id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          AWS = aws_cloudfront_origin_access_identity.oai[each.key].iam_arn
        }
        Action   = "s3:GetObject"
        Resource = "${each.value.bucket_arn}/*"
      }
    ]
  })
}