# Get an existing vpc id
data "aws_vpc" "current_vpc" {
  id = var.vpc_id
}

# Get account information
data "aws_caller_identity" "current" {}

# AWS Transfer Server Setup
resource "aws_transfer_server" "aws_ftp" {
  # checkov:skip=CKV_AWS_164:transferwise server need to be publically accessible
  identity_provider_type = var.aws_transfer_server_identity_provider_type
  endpoint_type          = var.aws_transfer_server_endpoint_type
  url                    = aws_api_gateway_stage.aws_transfer_server_api_gateway_stage.invoke_url
  logging_role           = aws_iam_role.aws_transfer_server_logging_role.arn
  invocation_role        = aws_iam_role.aws_transfer_server_invocation_role.arn
  security_policy_name   = var.security_policy_name

  tags = {
    Name         = "${var.environment}-${var.service_name}"
    environment  = var.environment
    service_name = var.service_name
    terraformed  = "true"
  }
}

data "aws_iam_policy_document" "aws_transfer_server_logging_assume_role_policy_document" {
  statement {
    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type        = "Service"
      identifiers = [
        "transfer.amazonaws.com",
      ]
    }
  }
}

data "aws_iam_policy_document" "aws_transfer_server_logging_role_policy_document" {
  statement {
    actions = [
      "logs:CreateLogGroup",
      "logs:CreateLogStream",
      "logs:DescribeLogStreams",
      "logs:PutLogEvents"
    ]

    effect    = "Allow"
    resources = [
      "arn:aws:logs:*:*:log-group:/aws/transfer/*"
    ]
  }
}

resource "aws_iam_role" "aws_transfer_server_logging_role" {
  name               = "${var.environment}-${var.service_name}-logging-role"
  assume_role_policy = data.aws_iam_policy_document.aws_transfer_server_logging_assume_role_policy_document.json
}

resource "aws_iam_policy" "aws_transfer_server_logging_role_policy" {
  name        = "${var.environment}-${var.service_name}-logging-role-policy"
  description = "AWS transfer server logging role policy"
  policy      = data.aws_iam_policy_document.aws_transfer_server_logging_role_policy_document.json
}

resource "aws_iam_role_policy_attachment" "aws_transfer_server_logging_role_attachment" {
  policy_arn = aws_iam_policy.aws_transfer_server_logging_role_policy.arn
  role       = aws_iam_role.aws_transfer_server_logging_role.name
}


data "aws_iam_policy_document" "aws_transfer_server_invocation_assume_role_policy_document" {
  statement {
    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type        = "Service"
      identifiers = [
        "transfer.amazonaws.com",
      ]
    }
  }
}

data "aws_iam_policy_document" "aws_transfer_server_invocation_role_policy_document" {
  statement {
    actions = [
      "apigateway:GET"
    ]

    effect    = "Allow"
    resources = [
      aws_api_gateway_stage.aws_transfer_server_api_gateway_stage.arn
    ]
  }

  statement {
    actions = [
      "execute-api:Invoke"
    ]

    effect    = "Allow"
    resources = [
      "${aws_api_gateway_stage.aws_transfer_server_api_gateway_stage.execution_arn}/GET/*"

    ]
  }
}

resource "aws_iam_role" "aws_transfer_server_invocation_role" {
  name               = "${var.environment}-${var.service_name}-invocation-role"
  assume_role_policy = data.aws_iam_policy_document.aws_transfer_server_invocation_assume_role_policy_document.json
}

resource "aws_iam_policy" "aws_transfer_server_invocation_role_policy" {
  name        = "${var.environment}-${var.service_name}-invocation-role-policy"
  description = "AWS transfer server invocation role policy"
  policy      = data.aws_iam_policy_document.aws_transfer_server_invocation_role_policy_document.json
}

resource "aws_iam_role_policy_attachment" "aws_transfer_server_invocation_role_attachment" {
  policy_arn = aws_iam_policy.aws_transfer_server_invocation_role_policy.arn
  role       = aws_iam_role.aws_transfer_server_invocation_role.name
}


# API Gateway Setup
resource "aws_api_gateway_rest_api" "aws_transfer_server_rest_api" {
  name        = "${var.environment}-${var.service_name}"
  description = "API used for GetUserConfig requests"

  endpoint_configuration {
    types = ["REGIONAL"]
  }

  api_key_source = "HEADER"

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

  lifecycle {
    create_before_destroy = true
  }
}

# API Gateway Resources. /servers/{serverId}/users/{username}/config
resource "aws_api_gateway_resource" "aws_transfer_server_api_gateway_resource_servers" {
  rest_api_id = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  parent_id   = aws_api_gateway_rest_api.aws_transfer_server_rest_api.root_resource_id
  path_part   = "servers"
}

resource "aws_api_gateway_resource" "aws_transfer_server_aws_api_gateway_resource_serverid" {
  rest_api_id = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  parent_id   = aws_api_gateway_resource.aws_transfer_server_api_gateway_resource_servers.id
  path_part   = "{serverId}"
}

resource "aws_api_gateway_resource" "aws_transfer_server_api_gateway_resource_users" {
  rest_api_id = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  parent_id   = aws_api_gateway_resource.aws_transfer_server_aws_api_gateway_resource_serverid.id
  path_part   = "users"
}

resource "aws_api_gateway_resource" "aws_transfer_server_aws_api_gateway_resource_username" {
  rest_api_id = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  parent_id   = aws_api_gateway_resource.aws_transfer_server_api_gateway_resource_users.id
  path_part   = "{username}"
}

resource "aws_api_gateway_resource" "aws_transfer_server_api_gateway_resource_config" {
  rest_api_id = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  parent_id   = aws_api_gateway_resource.aws_transfer_server_aws_api_gateway_resource_username.id
  path_part   = "config"
}

# API Gateway Resources method. /servers/{serverId}/users/{username}/config - GET
resource "aws_api_gateway_method" "aws_transfer_server_api_gateway_method" {
  rest_api_id   = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  resource_id   = aws_api_gateway_resource.aws_transfer_server_api_gateway_resource_config.id
  http_method   = "GET"
  authorization = "AWS_IAM"

  request_parameters = {
    "method.request.querystring.protocol" = false
    "method.request.querystring.sourceIp" = false
    "method.request.header.Password"      = false
  }

  request_validator_id = aws_api_gateway_request_validator.get.id
}

resource "aws_api_gateway_request_validator" "get" {
  name                        = "${var.environment}-${var.service_name}-request-validator"
  rest_api_id                 = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  validate_request_body       = true
  validate_request_parameters = true
}

# API Gateway Resources method model
resource "aws_api_gateway_model" "aws_transfer_server_api_gateway_model" {
  rest_api_id  = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  name         = "UserConfigResponseModel"
  description  = "API response for GetUserConfig"
  content_type = "application/json"
  schema       = file("${path.module}/${var.aws_transfer_server_api_gateway_model_json_schema}")
}

# API Gateway method response
resource "aws_api_gateway_method_response" "aws_transfer_server_api_gateway_method_response" {
  rest_api_id = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  resource_id = aws_api_gateway_resource.aws_transfer_server_api_gateway_resource_config.id
  http_method = aws_api_gateway_method.aws_transfer_server_api_gateway_method.http_method
  status_code = "200"

  response_models = {
    "application/json" = "UserConfigResponseModel"
  }
}

resource "aws_api_gateway_integration_response" "aws_transfer_server_api_gateway_integration_response" {
  rest_api_id = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  resource_id = aws_api_gateway_resource.aws_transfer_server_api_gateway_resource_config.id
  http_method = aws_api_gateway_method.aws_transfer_server_api_gateway_method.http_method
  status_code = aws_api_gateway_method_response.aws_transfer_server_api_gateway_method_response.status_code
}


# We now need to give the API Gateway permission to invoke the lambda function
resource "aws_lambda_permission" "aws_transfer_server_api_gateway_lamnda_permission" {
  statement_id  = "AllowAPIGatewayInvoke"
  action        = "lambda:InvokeFunction"
  function_name = var.aws_transfer_server_api_gateway_lambda_arn
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_rest_api.aws_transfer_server_rest_api.execution_arn}/*"
}


# API Gateway integration
resource "aws_api_gateway_integration" "aws_transfer_server_api_gateway_integration" {
  rest_api_id             = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  resource_id             = aws_api_gateway_resource.aws_transfer_server_api_gateway_resource_config.id
  http_method             = aws_api_gateway_method.aws_transfer_server_api_gateway_method.http_method
  type                    = "AWS"
  uri                     = var.aws_transfer_server_api_gateway_lambda_invoke_arn
  integration_http_method = "POST"

  request_templates = {
    "application/json" = file("${path.module}/${var.aws_transfer_server_api_gateway_request_template_json_schema}")
  }
}

# API Gateway deployment
resource "aws_api_gateway_deployment" "aws_transfer_server_api_gateway_deployment_get" {
  rest_api_id = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_cloudwatch_log_group" "aws_ftp_api_log_group" {
  name = "/aws/apigateway/${var.environment}-${var.service_name}"

  retention_in_days = 365

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

# API Gateway Stage
resource "aws_api_gateway_stage" "aws_transfer_server_api_gateway_stage" {
  # checkov:skip=CKV_AWS_73:we do not need xray enabled
  # checkov:skip=CKV_AWS_120:we do not need caching enabled
  # checkov:skip=CKV2_AWS_51:we don't use this
  # checkov:skip=CKV2_AWS_51:same as above
  stage_name    = "prod"
  rest_api_id   = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  deployment_id = aws_api_gateway_deployment.aws_transfer_server_api_gateway_deployment_get.id

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

  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.aws_ftp_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",
      "path" : "$context.path", "resourcePath" : "$context.resourcePath", "status" : "$context.status",
      "protocol" : "$context.protocol", "responseLength" : "$context.responseLength"
    })
  }
}

data "aws_wafv2_web_acl" "waf" {
  name  = "${var.block_waf_enabled ? "${var.environment}-orcd-waf-block" : "${var.environment}-orcd-waf-count-only"}"
  scope = "REGIONAL"
}

resource "aws_wafv2_web_acl_association" "api_gateway_waf_association" {
  resource_arn = aws_api_gateway_stage.aws_transfer_server_api_gateway_stage.arn
  web_acl_arn  = data.aws_wafv2_web_acl.waf.arn
}

resource "aws_api_gateway_method_settings" "all" {
  # checkov:skip=CKV_AWS_225:we do not want caching enabled
  # checkov:skip=CKV_AWS_308:no caching, no enctyption needed
  rest_api_id = aws_api_gateway_rest_api.aws_transfer_server_rest_api.id
  stage_name  = aws_api_gateway_stage.aws_transfer_server_api_gateway_stage.stage_name
  method_path = "*/*"

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