# API Gateway Resource Policy Data Source
data "aws_iam_policy_document" "api_gateway_resource_policy" {
  statement {
    effect = "Allow"
    principals {
      type        = "*"
      identifiers = ["*"]
    }
    actions   = ["execute-api:Invoke"]
    resources = ["execute-api:/*"]

    condition {
      test     = "IpAddress"
      variable = "aws:SourceIp"
      values   = var.jira_egress_ips
    }
  }
}

# API Gateway REST API
resource "aws_api_gateway_rest_api" "jira_webhook_rest_api" {
  name        = "${var.service_name}-api"
  description = "Jira Webhook to GitHub Issues REST API Gateway"
  endpoint_configuration {
    types = ["REGIONAL"]
  }

  policy = data.aws_iam_policy_document.api_gateway_resource_policy.json

  lifecycle {
    create_before_destroy = true
  }
  tags = {
    application_family = var.application_family
    environment        = var.environment
    service_name       = var.service_name
    terraformed        = true
  }
}

# API Gateway Resource
resource "aws_api_gateway_resource" "jira_webhook_rest_api_resource" {
  rest_api_id = aws_api_gateway_rest_api.jira_webhook_rest_api.id
  parent_id   = aws_api_gateway_rest_api.jira_webhook_rest_api.root_resource_id
  path_part   = "jira-webhook"
}

# Request Validator
resource "aws_api_gateway_request_validator" "validator" {
  rest_api_id                 = aws_api_gateway_rest_api.jira_webhook_rest_api.id
  name                        = "${var.service_name}-validator"
  validate_request_body       = false
  validate_request_parameters = false
}

# Custom Authorizer
resource "aws_api_gateway_authorizer" "jira_webhook_rest_api_authorizer" {
  name                   = "${var.environment}-${var.service_name}-authorizer"
  rest_api_id            = aws_api_gateway_rest_api.jira_webhook_rest_api.id
  authorizer_uri         = module.lambda_authorizer.lambda_invoke_arn
  authorizer_credentials = aws_iam_role.authorizer_invocation_role.arn
  type                   = "REQUEST"

  # Disable caching since signatures are unique per request
  authorizer_result_ttl_in_seconds = 0
}

# IAM Assume Role Policy Document for Authorizer Invocation
data "aws_iam_policy_document" "authorizer_invocation_assume_role" {
  statement {
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["apigateway.amazonaws.com"]
    }
    actions = ["sts:AssumeRole"]
  }
}

# IAM Role for API Gateway to invoke authorizer
resource "aws_iam_role" "authorizer_invocation_role" {
  name               = "${var.environment}-${var.service_name}-authorizer-invocation"
  assume_role_policy = data.aws_iam_policy_document.authorizer_invocation_assume_role.json

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

# IAM Policy Document for API Gateway to invoke Lambda authorizer
data "aws_iam_policy_document" "authorizer_invocation_policy" {
  statement {
    effect    = "Allow"
    actions   = ["lambda:InvokeFunction"]
    resources = [module.lambda_authorizer.lambda_arn]
  }
}

# IAM Policy for API Gateway to invoke Lambda authorizer
resource "aws_iam_role_policy" "authorizer_invocation_policy" {
  name   = "InvokeLambda"
  role   = aws_iam_role.authorizer_invocation_role.id
  policy = data.aws_iam_policy_document.authorizer_invocation_policy.json
}

# Lambda Permission for Authorizer
resource "aws_lambda_permission" "jira_webhook_rest_api_authorizer_lambda_gateway_permission" {
  statement_id  = "AllowAPIGatewayInvoke"
  action        = "lambda:InvokeFunction"
  function_name = module.lambda_authorizer.lambda_name
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_rest_api.jira_webhook_rest_api.execution_arn}/*"
}

# API Gateway Method
resource "aws_api_gateway_method" "jira_webhook_rest_api_method" {
  rest_api_id          = aws_api_gateway_rest_api.jira_webhook_rest_api.id
  resource_id          = aws_api_gateway_resource.jira_webhook_rest_api_resource.id
  request_validator_id = aws_api_gateway_request_validator.validator.id
  http_method          = "POST"
  authorization        = "CUSTOM"
  authorizer_id        = aws_api_gateway_authorizer.jira_webhook_rest_api_authorizer.id
}

# API Gateway Integration - SQS
resource "aws_api_gateway_integration" "jira_webhook_rest_api_integration" {
  rest_api_id             = aws_api_gateway_rest_api.jira_webhook_rest_api.id
  resource_id             = aws_api_gateway_resource.jira_webhook_rest_api_resource.id
  http_method             = aws_api_gateway_method.jira_webhook_rest_api_method.http_method
  integration_http_method = "POST"
  type                    = "AWS"
  credentials             = aws_iam_role.api_gateway_sqs_role.arn
  uri                     = "arn:aws:apigateway:${var.aws_region}:sqs:path/${data.aws_caller_identity.current.account_id}/${module.jira_webhook_queue.queue_name}"

  request_parameters = {
    "integration.request.header.Content-Type" = "'application/x-www-form-urlencoded'"
  }

  request_templates = {
    "application/json" = "Action=SendMessage&MessageBody=$input.body"
  }

  passthrough_behavior = "NEVER"
}

# Integration Response
resource "aws_api_gateway_integration_response" "integration_response_200" {
  rest_api_id = aws_api_gateway_rest_api.jira_webhook_rest_api.id
  resource_id = aws_api_gateway_resource.jira_webhook_rest_api_resource.id
  http_method = aws_api_gateway_method.jira_webhook_rest_api_method.http_method
  status_code = aws_api_gateway_method_response.response_200.status_code

  response_templates = {
    "application/json" = jsonencode({
      message = "Message sent to SQS"
    })
  }

  depends_on = [
    aws_api_gateway_integration.jira_webhook_rest_api_integration
  ]
}

# Method Response
resource "aws_api_gateway_method_response" "response_200" {
  rest_api_id = aws_api_gateway_rest_api.jira_webhook_rest_api.id
  resource_id = aws_api_gateway_resource.jira_webhook_rest_api_resource.id
  http_method = aws_api_gateway_method.jira_webhook_rest_api_method.http_method
  status_code = "200"
}

# CloudWatch Log Group for API Gateway
resource "aws_cloudwatch_log_group" "rest_api_log_group" {
  name              = "/aws/apigateway/${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 Deployment
resource "aws_api_gateway_deployment" "jira_webhook_rest_api_deployment" {
  rest_api_id = aws_api_gateway_rest_api.jira_webhook_rest_api.id
  description = "Deployment for Jira Webhook API Gateway"

  triggers = {
    redeployment = sha1(jsonencode([
      aws_api_gateway_resource.jira_webhook_rest_api_resource.id,
      aws_api_gateway_method.jira_webhook_rest_api_method.id,
      aws_api_gateway_integration.jira_webhook_rest_api_integration.id,
    ]))
  }

  lifecycle {
    create_before_destroy = true
  }
}

# API Gateway Stage
resource "aws_api_gateway_stage" "jira_webhook_rest_api_stage" {
  # checkov:skip=CKV2_AWS_51 Client certificate authentication not required for webhook
  deployment_id = aws_api_gateway_deployment.jira_webhook_rest_api_deployment.id
  rest_api_id   = aws_api_gateway_rest_api.jira_webhook_rest_api.id
  stage_name    = var.environment

  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.rest_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 = {
    application_family = var.application_family
    environment        = var.environment
    service_name       = var.service_name
    terraformed        = true
  }
}

# Attach WAF to API Gateway Stage
resource "aws_wafv2_web_acl_association" "api_gateway_waf_association" {
  resource_arn = aws_api_gateway_stage.jira_webhook_rest_api_stage.arn
  web_acl_arn  = data.aws_wafv2_web_acl.waf.arn
}

# Method Settings for API Gateway
resource "aws_api_gateway_method_settings" "jira_webhook_api_gateway_method_settings" {
  rest_api_id = aws_api_gateway_rest_api.jira_webhook_rest_api.id
  stage_name  = aws_api_gateway_stage.jira_webhook_rest_api_stage.stage_name
  method_path = "*/*"

  settings {
    metrics_enabled = true
    logging_level   = "INFO"
  }
}

# IAM Assume Role Policy Document for API Gateway SQS Role
data "aws_iam_policy_document" "api_gateway_sqs_assume_role" {
  statement {
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["apigateway.amazonaws.com"]
    }
    actions = ["sts:AssumeRole"]
  }
}

# IAM Role for API Gateway to send messages to SQS
resource "aws_iam_role" "api_gateway_sqs_role" {
  name               = "${var.environment}-${var.service_name}-apigw-sqs"
  assume_role_policy = data.aws_iam_policy_document.api_gateway_sqs_assume_role.json

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

# IAM Policy for API Gateway to send to SQS
data "aws_iam_policy_document" "api_gateway_sqs_policy" {
  statement {
    effect = "Allow"
    actions = [
      "sqs:SendMessage",
    ]
    resources = [
      module.jira_webhook_queue.queue_arn
    ]
  }
}

resource "aws_iam_role_policy" "api_gateway_sqs_policy" {
  name   = "SQS-${var.environment}-${var.service_name}"
  role   = aws_iam_role.api_gateway_sqs_role.id
  policy = data.aws_iam_policy_document.api_gateway_sqs_policy.json
}
