provider "aws" {
  region = "us-east-1"
}

# Caller Identity
data "aws_caller_identity" "current" {}

data "aws_vpc" "vpc" {
  tags = {
    Name = "prod"
  }
}

# Terraform backends cannot contain interpolations - of the form ${var.environment}-${var.service_name}-state
terraform {
  backend "s3" {
    bucket  = "orcd-terraform-state"
    key     = "prod/lambda-sme-ext-meta/terraform.tfstate"
    region  = "us-east-1"
    encrypt = true
  }
}

resource "aws_api_gateway_rest_api" "generate_ddex_api" {
  #checkov:skip=CKV_AWS_237:Ensure Create before destroy for API GATEWAY. It's enabled line 160
  name        = "${var.environment}-sme-ext-meta-generate-ddex"
  description = "terraformed"

  endpoint_configuration {
    types            = ["PRIVATE"]
    vpc_endpoint_ids = ["vpce-04f8c4be29fb2bd59"]
  }
}

resource "aws_api_gateway_rest_api_policy" "generate_ddex_api_resource_policy" {
  rest_api_id = aws_api_gateway_rest_api.generate_ddex_api.id

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "execute-api:Invoke",
      "Resource": "${aws_api_gateway_rest_api.generate_ddex_api.execution_arn}/*/GET/upc/*",
      "Condition": {
        "IpAddress": {
          "aws:VpcSourceIp": [
              "192.168.40.0/22",
              "192.168.32.0/24",
              "10.40.0.0/22",
              "10.10.40.0/22",
              "10.100.112.0/21",
              "10.100.72.0/21",
              "10.100.88.0/21"
          ]
        }
      }
    }
  ]
}
EOF
}

# API Gateway Resources. /upc/{upc}
resource "aws_api_gateway_resource" "aws_api_gateway_resource_upc" {
  rest_api_id = aws_api_gateway_rest_api.generate_ddex_api.id
  parent_id   = aws_api_gateway_rest_api.generate_ddex_api.root_resource_id
  path_part   = "upc"
}

resource "aws_api_gateway_resource" "aws_api_gateway_resource_upc_value" {
  rest_api_id = aws_api_gateway_rest_api.generate_ddex_api.id
  parent_id   = aws_api_gateway_resource.aws_api_gateway_resource_upc.id
  path_part   = "{upc}"
}

# API Gateway Resources method. /upc/{upc} - GET
resource "aws_api_gateway_method" "generate_ddex_api_gateway_method" {
  # checkov:skip=CKV2_AWS_53:can be ignored because the validation is being handled in the lambda function
  # checkov:skip=CKV_AWS_59:Access to public API Gateway methods is limited by IP addresses.
  rest_api_id   = aws_api_gateway_rest_api.generate_ddex_api.id
  resource_id   = aws_api_gateway_resource.aws_api_gateway_resource_upc_value.id
  http_method   = "GET"
  authorization = "NONE"
}

resource "aws_lambda_permission" "generate_ddex_lambda_api_gateway_permission" {
  statement_id  = "AllowAPIGatewayInvoke"
  action        = "lambda:InvokeFunction"
  function_name = module.lambda_generate_ddex.lambda_arn
  principal     = "apigateway.amazonaws.com"
  source_arn    = format(
    "arn:aws:execute-api:us-east-1:%s:%s/*/GET/upc/{upc}",
    data.aws_caller_identity.current.account_id,
    aws_api_gateway_rest_api.generate_ddex_api.id
  )
}

# API Gateway integration
resource "aws_api_gateway_integration" "generate_ddex_api_stage" {
  rest_api_id             = aws_api_gateway_rest_api.generate_ddex_api.id
  resource_id             = aws_api_gateway_resource.aws_api_gateway_resource_upc_value.id
  http_method             = aws_api_gateway_method.generate_ddex_api_gateway_method.http_method
  type                    = "AWS_PROXY"
  uri                     = module.lambda_generate_ddex.lambda_invoke_arn
  integration_http_method = "POST"
}

# API Gateway deployment
resource "aws_api_gateway_deployment" "generate_ddex_api_deployment" {
  rest_api_id = aws_api_gateway_rest_api.generate_ddex_api.id

  triggers = {
    redeployment = sha1(jsonencode(aws_api_gateway_rest_api.generate_ddex_api))
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_cloudwatch_log_group" "generate_ddex_api_log_group" {
  name              = "/aws/apigateway/${var.environment}-${var.service_name}"
  retention_in_days = 365
  tags = {
    application_family = var.application_family
    environment        = var.environment
    service_name       = var.service_name
    terraformed        = true
  }
}

# API Gateway Stage
resource "aws_api_gateway_stage" "generate_ddex_api_gateway_stage" {
  # checkov:skip=CKV2_AWS_51:isn't relevant because the backend is a lambda function
  stage_name         = "sme-ext-meta-generate-ddex"
  rest_api_id        = aws_api_gateway_rest_api.generate_ddex_api.id
  deployment_id      = aws_api_gateway_deployment.generate_ddex_api_deployment.id
  cache_cluster_size = 0.5
  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.generate_ddex_api_log_group.arn
    format = jsonencode({
      "requestId" : "$context.requestId",
      "ip" : "$context.identity.sourceIp",
      "caller" : "$context.identity.caller",
      "user" : "$context.identity.user",
      "requestTime" : "$context.requestTime",
      "httpMethod" : "$context.httpMethod",
      "resourcePath" : "$context.resourcePath",
      "status" : "$context.status",
      "protocol" : "$context.protocol",
      "responseLength" : "$context.responseLength",
      "integrationErrorMessage" : "$context.integrationErrorMessage"
    })
  }

  tags = {
    environment  = var.environment
    service_name = var.service_name
    terraformed  = "true"
  }
}

resource "aws_api_gateway_method_settings" "generate_ddex_api_gateway_settings" {
  rest_api_id = aws_api_gateway_rest_api.generate_ddex_api.id
  stage_name  = aws_api_gateway_stage.generate_ddex_api_gateway_stage.stage_name
  method_path = "*/*"

  settings {
    metrics_enabled        = true
    logging_level          = "ERROR"
    throttling_rate_limit  = 10000
    throttling_burst_limit = 5000
    cache_data_encrypted   = true
  }
}
