data "aws_caller_identity" "current" {}

data "aws_iam_policy_document" "assume_role" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["apigateway.amazonaws.com"]
    }
  }
}

resource "aws_iam_role" "api_gateway_role" {
  name               = "api-gateway-${var.api_gateway_name}"
  assume_role_policy = "${data.aws_iam_policy_document.assume_role.json}"
}

data "aws_iam_policy_document" "api_gateway_s3_policy" {
  statement {
    effect    = "Allow"
    actions   = [
      "s3:GetBucketAcl",
      "s3:GetBucketCORS",
      "s3:GetBucketLocation",
      "s3:GetBucketLogging",
      "s3:GetBucketNotification",
      "s3:GetBucketPolicy",
      "s3:GetBucketRequestPayment",
      "s3:GetBucketTagging",
      "s3:GetBucketVersioning",
      "s3:GetBucketWebsite",
      "s3:GetLifecycleConfiguration",
      "s3:GetObject",
      "s3:GetObjectAcl",
      "s3:GetObjectTorrent",
      "s3:GetObjectVersion",
      "s3:GetObjectVersionAcl",
      "s3:GetObjectVersionTorrent",
      "s3:ListAllMyBuckets",
      "s3:ListBucket",
      "s3:ListBucketMultipartUploads",
      "s3:ListBucketVersions",
      "s3:ListMultipartUploadParts"
    ]
    resources = [
      "arn:aws:s3:::${var.s3_bucket}/${var.s3_path}",
      "arn:aws:s3:::${var.s3_bucket}/${var.s3_path}/*"
    ]
  }
}

resource "aws_iam_policy" "api_gateway_s3_policy" {
  name   = "api-gateway-${var.api_gateway_name}"
  policy = "${data.aws_iam_policy_document.api_gateway_s3_policy.json}"
}

resource "aws_iam_role_policy_attachment" "api_gateway_s3_policy_attachment" {
  role       = "${aws_iam_role.api_gateway_role.name}"
  policy_arn = "${aws_iam_policy.api_gateway_s3_policy.arn}"
}

resource "aws_iam_role_policy_attachment" "api_gateway_cloudwatch_policy_attachment" {
  role       = "${aws_iam_role.api_gateway_role.name}"
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
}

resource "aws_api_gateway_rest_api" "new_release_json" {
  name        = "${var.api_gateway_name}"
  description = "New releases JSON API"
}

resource "aws_api_gateway_resource" "new_release" {
  rest_api_id = "${aws_api_gateway_rest_api.new_release_json.id}"
  parent_id   = "${aws_api_gateway_rest_api.new_release_json.root_resource_id}"
  path_part   = "releases"
}

resource "aws_api_gateway_method" "new_release_method" {
  rest_api_id   = "${aws_api_gateway_rest_api.new_release_json.id}"
  resource_id   = "${aws_api_gateway_resource.new_release.id}"
  http_method   = "GET"
  authorization = "AWS_IAM"

  # The parameter must be enabled in the method before usage in integration.
  request_parameters = {
    "method.request.path.file" = true
  }
}

resource "aws_api_gateway_integration" "api_integration" {
  rest_api_id             = "${aws_api_gateway_rest_api.new_release_json.id}"
  resource_id             = "${aws_api_gateway_resource.new_release.id}"
  http_method             = "${aws_api_gateway_method.new_release_method.http_method}"
  integration_http_method = "${aws_api_gateway_method.new_release_method.http_method}"
  type                    = "AWS"
  uri                     = "arn:aws:apigateway:${var.s3_region}:s3:path/${var.s3_bucket}/${var.s3_path}/${var.s3_object}"
  credentials             = "${aws_iam_role.api_gateway_role.arn}"

  request_parameters      = {
    "integration.request.path.file" = "method.request.path.file"
  }
}

resource "aws_api_gateway_method_response" "response_200" {
  rest_api_id     = "${aws_api_gateway_rest_api.new_release_json.id}"
  resource_id     = "${aws_api_gateway_resource.new_release.id}"
  http_method     = "${aws_api_gateway_method.new_release_method.http_method}"

  status_code     = "200"
  response_models = {
    "application/json" = "Empty"
  }
}

resource "aws_api_gateway_integration_response" "ResourceMethodIntegration200" {
  rest_api_id = "${aws_api_gateway_rest_api.new_release_json.id}"
  resource_id = "${aws_api_gateway_resource.new_release.id}"
  http_method = "${aws_api_gateway_method.new_release_method.http_method}"
  status_code = "${aws_api_gateway_method_response.response_200.status_code}"
  depends_on  = ["aws_api_gateway_integration.api_integration"]

  # response_templates   = {
  #   "application/json" = "null"
  # }
}

# Add swagger spec endpoint
resource "aws_api_gateway_resource" "spec" {
  rest_api_id = "${aws_api_gateway_rest_api.new_release_json.id}"
  parent_id   = "${aws_api_gateway_rest_api.new_release_json.root_resource_id}"
  path_part   = "spec"
}

resource "aws_api_gateway_method" "spec" {
  rest_api_id   = "${aws_api_gateway_rest_api.new_release_json.id}"
  resource_id   = "${aws_api_gateway_resource.spec.id}"
  http_method   = "GET"
  authorization = "AWS_IAM"

  # The parameter must be enabled in the method before usage in integration.
  request_parameters = {
    "method.request.path.file" = true
  }
}

resource "aws_api_gateway_integration" "spec_integration" {
  rest_api_id             = "${aws_api_gateway_rest_api.new_release_json.id}"
  resource_id             = "${aws_api_gateway_resource.spec.id}"
  http_method             = "${aws_api_gateway_method.spec.http_method}"
  integration_http_method = "${aws_api_gateway_method.spec.http_method}"
  type                    = "AWS"
  uri                     = "arn:aws:apigateway:${var.s3_region}:s3:path/${var.s3_bucket}/${var.s3_path}/${var.s3_spec_object}"
  credentials             = "${aws_iam_role.api_gateway_role.arn}"

  request_parameters      = {
    "integration.request.path.file" = "method.request.path.file"
  }
}

resource "aws_api_gateway_method_response" "spec_200" {
  rest_api_id     = "${aws_api_gateway_rest_api.new_release_json.id}"
  resource_id     = "${aws_api_gateway_resource.spec.id}"
  http_method     = "${aws_api_gateway_method.spec.http_method}"

  status_code     = "200"
  response_models = {
    "application/x-yaml" = "Empty"
  }
}

resource "aws_api_gateway_integration_response" "SpecMethodIntegration200" {
  rest_api_id = "${aws_api_gateway_rest_api.new_release_json.id}"
  resource_id = "${aws_api_gateway_resource.spec.id}"
  http_method = "${aws_api_gateway_method.spec.http_method}"
  status_code = "${aws_api_gateway_method_response.spec_200.status_code}"
  depends_on  = ["aws_api_gateway_integration.spec_integration"]
}

resource "aws_api_gateway_deployment" "api_deployment" {
  rest_api_id = "${aws_api_gateway_rest_api.new_release_json.id}"
  stage_name  = "default_stage"
  depends_on  = ["aws_api_gateway_method.new_release_method"]
}

resource "aws_api_gateway_domain_name" "api_domain_name" {
  domain_name     = "${var.api_gateway_domain_name}"
  certificate_arn = "${var.api_gateway_certificate_arn}"
}

resource "aws_route53_record" "api_gateway_dns_record" {
  name = "${aws_api_gateway_domain_name.api_domain_name.domain_name}"
  zone_id = "${var.aws_route53_params["zone_id"]}"
  type    = "${var.aws_route53_params["type"]}"

  alias {
    name                   = "${aws_api_gateway_domain_name.api_domain_name.cloudfront_domain_name}"
    zone_id                = "${aws_api_gateway_domain_name.api_domain_name.cloudfront_zone_id}"
    evaluate_target_health = true
  }
}

resource "aws_api_gateway_base_path_mapping" "base_path_mapping" {
  api_id      = "${aws_api_gateway_rest_api.new_release_json.id}"
  stage_name  = "${aws_api_gateway_deployment.api_deployment.stage_name}"
  domain_name = "${aws_api_gateway_domain_name.api_domain_name.domain_name}"
}

# Create an IAM user with permissions to invoke this API endpoint
resource "aws_iam_user" "invoke_api_user" {
  name = "${var.invoke_api_iam_user_name}"
}

data "aws_iam_policy_document" "invoke_api_policy" {
  statement {
    effect    = "Allow"
    actions   = [
      "execute-api:Invoke",
      "execute-api:GET",
    ]
    resources = [
      "arn:aws:execute-api:::${aws_api_gateway_rest_api.new_release_json.id}/*/${aws_api_gateway_method.new_release_method.http_method}/${aws_api_gateway_resource.new_release.path_part}",
      "arn:aws:execute-api:${var.s3_region}:${data.aws_caller_identity.current.account_id}:${aws_api_gateway_rest_api.new_release_json.id}/${aws_api_gateway_deployment.api_deployment.stage_name}/${aws_api_gateway_method.new_release_method.http_method}/${aws_api_gateway_resource.new_release.path_part}",
    ]
  }
}

resource "aws_iam_policy" "invoke_api_policy" {
  name   = "api-gateway-invoke-${var.api_gateway_name}"
  policy = "${data.aws_iam_policy_document.invoke_api_policy.json}"
}

resource "aws_iam_user_policy_attachment" "invoke_api_gateway_policy_attachment" {
  user       = "${aws_iam_user.invoke_api_user.name}"
  policy_arn = "${aws_iam_policy.invoke_api_policy.arn}"
}

data "aws_wafv2_web_acl" "waf" {
  name  = "prod-public-shared-regional-waf-block"
  scope = "REGIONAL"
}

resource "aws_wafv2_web_acl_association" "api_gateway_waf_association" {
  resource_arn = "${aws_api_gateway_rest_api.new_release_json.arn}/stages/default_stage"
  web_acl_arn  = data.aws_wafv2_web_acl.waf.arn
}
