provider "aws" {
  region = var.aws_region
}

data "aws_caller_identity" "current" {}

terraform {
  backend "s3" {
    bucket  = "orcd-terraform-state"
    key     = "qa/lambda-moneyhub/terraform.tfstate"
    region  = "us-east-1"
    encrypt = true
  }
}

module "vpc_info" {
  source      = "git@github.com:theorchard/terraform-vpc-info.git//?ref=3.2.2"
  environment = var.environment
}

# Custom reports SQS

module "sqs_moneyhub_custom_reports" {
  source = "git@github.com:theorchard/terraform-sqs.git//?ref=2.4.1"

  environment                    = var.environment
  application_family             = var.application_family
  queue_name                     = var.sqs_custom_reports_name
  sqs_max_message_size           = 262144
  sqs_fifo_queue                 = "false"
  sqs_visibility_timeout_seconds = var.lambda_timeout

  sqs_deadletter_enabled               = "true"
  deadletter_message_retention_seconds = 86400
  deadletter_delay_seconds             = 10
  deadletter_max_message_size          = 262144
  deadletter_receive_wait_time_seconds = 10
}

# Custom Reports Lambda

module "lambda_moneyhub_custom_reports" {
  source = "git@github.com:theorchard/terraform-lambda.git//?ref=5.2.1"

  environment               = var.environment
  application_family        = var.application_family
  lambda_function_timeout   = var.lambda_timeout
  use_container_image       = true
  lambda_description        = "Generate custom reports"
  lambda_name               = var.lambda_custom_reports_name
  datadog_advanced_enabled  = true
  vpc_enabled               = true
  vpc_id                    = module.vpc_info.vpc_id
  vpc_subnet_ids            = module.vpc_info.default_private_subnet_ids
  vpc_create_security_group = true

  sqs_event_enabled                  = true
  event_source_mapping_resource_type = "sqs"
  event_source_mapping_queue_name    = module.sqs_moneyhub_custom_reports.queue_name
  event_source_mapping_batch_size    = 1

  lambda_function_reserved_concurrent_executions = 64
  lambda_function_memory_size                    = 512
  lambda_function_ephemeral_storage_size         = 512

  lambda_function_environment_variables = {
    ENVIRONMENT              = var.environment
    OWS_PROFILE_ID           = var.ows_service_profile_id
    OWS_PROFILE_ROLES        = var.ows_profile_roles
    OWS_PROFILE_TYPE         = var.ows_service_profile_type
    SENTRY_DSN               = module.lambda_moneyhub_custom_reports_sentry_project.sentry_key_dsn_public_output
    SNOWFLAKE_ACCOUNT        = var.snowflake_account
    SNOWFLAKE_DATABASE       = var.snowflake_database
    SNOWFLAKE_SCHEMA         = var.snowflake_schema
    SNOWFLAKE_WAREHOUSE      = var.snowflake_warehouse
    SNOWFLAKE_ROLE           = var.snowflake_role
    SNOWFLAKE_USER           = var.snowflake_user
    SNOWFLAKE_PRIVATE_KEY    = var.snowflake_private_key
    SNOWFLAKE_KEY_PASSPHRASE = var.snowflake_key_passphrase
  }

  iam_managed_policy_attachments = [
    module.lambda_moneyhub_custom_reports_owsrequest.policy_arn_output,
    aws_iam_policy.moneyhub_attachments_bucket_write_access_policy.arn,
    aws_iam_policy.moneyhub_features_secrets_manager_policy.arn
  ]
}

module "custom_reports_m2m_secrets" {
  source = "git@github.com:theorchard/terraform-secrets-manager.git//modules/auth0m2m?ref=1.6.1"

  environment        = var.environment
  service_name       = var.lambda_custom_reports_name
  application_family = var.application_family
}

module "lambda_moneyhub_custom_reports_sentry_project" {
  source = "git@github.com:theorchard/terraform-sentry.git//?ref=4.1.2"

  environment        = var.environment
  application_family = var.application_family
  platform           = "python"
  service_name       = var.lambda_custom_reports_name
  teams              = [var.environment]
}

module "lambda_moneyhub_custom_reports_owsrequest" {
  source = "git@github.com:theorchard/terraform-owsrequest.git//?ref=1.1.0"

  environment_name = var.environment
  service_name     = var.lambda_custom_reports_name
}

module "lambda_moneyhub_custom_reports_secrets" {
  source   = "git@github.com:theorchard/terraform-secrets-manager.git//?ref=1.5.1"
  for_each = toset(var.secrets_manager_secret_names)

  environment                    = var.environment
  service_name                   = var.lambda_custom_reports_name
  secret_name                    = each.value
  application_family             = var.application_family
  secret_recovery_window_in_days = 7
}

# Generate Attachments SQS

module "sqs_moneyhub_generate_attachments" {
  source = "git@github.com:theorchard/terraform-sqs.git//?ref=2.4.1"

  environment                    = var.environment
  application_family             = var.application_family
  queue_name                     = var.sqs_generate_attachments_name
  sqs_max_message_size           = 262144
  sqs_fifo_queue                 = "false"
  sqs_visibility_timeout_seconds = var.lambda_timeout

  sqs_deadletter_enabled               = "true"
  deadletter_message_retention_seconds = 86400
  deadletter_delay_seconds             = 10
  deadletter_max_message_size          = 262144
  deadletter_receive_wait_time_seconds = 10
}

# Generate Attachments Lambda

module "lambda_moneyhub_generate_attachments" {
  source = "git@github.com:theorchard/terraform-lambda.git//?ref=5.2.1"

  environment               = var.environment
  application_family        = var.application_family
  lambda_function_timeout   = var.lambda_timeout
  use_container_image       = true
  lambda_description        = "Generate attachments to statement periods"
  lambda_name               = var.lambda_generate_attachments_name
  datadog_advanced_enabled  = true
  vpc_enabled               = true
  vpc_id                    = module.vpc_info.vpc_id
  vpc_subnet_ids            = module.vpc_info.default_private_subnet_ids
  vpc_create_security_group = true

  sqs_event_enabled                  = true
  event_source_mapping_resource_type = "sqs"
  event_source_mapping_queue_name    = module.sqs_moneyhub_generate_attachments.queue_name
  event_source_mapping_batch_size    = 1

  lambda_function_reserved_concurrent_executions = 64
  lambda_function_memory_size                    = 10240
  lambda_function_ephemeral_storage_size         = 10240

  lambda_function_environment_variables = {
    ENVIRONMENT              = var.environment
    OWS_PROFILE_ID           = var.ows_service_profile_id
    OWS_PROFILE_ROLES        = var.ows_profile_roles
    OWS_PROFILE_TYPE         = var.ows_service_profile_type
    SENTRY_DSN               = module.lambda_moneyhub_generate_attachments_sentry_project.sentry_key_dsn_public_output
    SNOWFLAKE_ACCOUNT        = var.snowflake_account
    SNOWFLAKE_DATABASE       = var.snowflake_database
    SNOWFLAKE_SCHEMA         = var.snowflake_schema
    SNOWFLAKE_WAREHOUSE      = var.snowflake_warehouse
    SNOWFLAKE_ROLE           = var.snowflake_role
    SNOWFLAKE_USER           = var.snowflake_user
    SNOWFLAKE_PRIVATE_KEY    = var.snowflake_private_key
    SNOWFLAKE_KEY_PASSPHRASE = var.snowflake_key_passphrase
  }

  iam_managed_policy_attachments = [
    module.lambda_moneyhub_generate_attachments_owsrequest.policy_arn_output,
    aws_iam_policy.moneyhub_attachments_bucket_write_access_policy.arn,
    aws_iam_policy.moneyhub_features_secrets_manager_policy.arn
  ]
}

module "generate_attachments_m2m_secrets" {
  source = "git@github.com:theorchard/terraform-secrets-manager.git//modules/auth0m2m?ref=1.6.1"

  environment        = var.environment
  service_name       = var.lambda_generate_attachments_name
  application_family = var.application_family
}

module "lambda_moneyhub_generate_attachments_sentry_project" {
  source = "git@github.com:theorchard/terraform-sentry.git//?ref=4.1.2"

  environment        = var.environment
  application_family = var.application_family
  platform           = "python"
  service_name       = var.lambda_generate_attachments_name
  teams              = [var.environment]
}

module "lambda_moneyhub_generate_attachments_owsrequest" {
  source = "git@github.com:theorchard/terraform-owsrequest.git//?ref=1.1.0"

  environment_name = var.environment
  service_name     = var.lambda_generate_attachments_name
}

module "lambda_moneyhub_generate_attachments_secrets" {
  source   = "git@github.com:theorchard/terraform-secrets-manager.git//?ref=1.5.1"
  for_each = toset(var.secrets_manager_secret_names)

  environment                    = var.environment
  service_name                   = var.lambda_generate_attachments_name
  secret_name                    = each.value
  application_family             = var.application_family
  secret_recovery_window_in_days = 7
}


# Internal Statement Attachments Lambda

module "lambda_moneyhub_internal_attachments" {
  source = "git@github.com:theorchard/terraform-lambda.git//?ref=5.2.1"

  environment               = var.environment
  application_family        = var.application_family
  lambda_function_timeout   = var.lambda_timeout
  use_container_image       = true
  lambda_description        = "Upload internal statement attachments to accounts and statement periods"
  lambda_name               = var.lambda_internal_attachments_name
  datadog_advanced_enabled  = true
  vpc_enabled               = true
  vpc_id                    = module.vpc_info.vpc_id
  vpc_subnet_ids            = module.vpc_info.default_private_subnet_ids
  vpc_create_security_group = true

  lambda_function_provisioned_concurrent_executions = var.lambda_function_provisioned_concurrent_executions
  lambda_function_provisioned_concurrency_alias     = var.lambda_function_provisioned_concurrency_alias
  lambda_function_reserved_concurrent_executions    = 64
  lambda_function_memory_size                       = 5120
  lambda_function_ephemeral_storage_size            = 5120

  lambda_function_environment_variables = {
    BUCKET_NAME                      = var.bucket_name
    DDB_WRITE_MAX_ATTEMPTS           = var.ddb_write_max_attempts
    EMAIL_SENDER                     = var.email_sender
    ENVIRONMENT                      = var.environment
    ERROR_ATTACHMENT_EMAIL_RECIPIENT = var.error_attachment_email_recipient
    IGNORE_ALL_EVENTS                = var.ignore_all_events
    OWS_PROFILE_ID                   = var.ows_service_profile_id
    OWS_PROFILE_ROLES                = var.ows_profile_roles
    OWS_PROFILE_TYPE                 = var.ows_service_profile_type
    SENTRY_DSN                       = module.lambda_moneyhub_internal_attachments_sentry_project.sentry_key_dsn_public_output
  }

  iam_managed_policy_attachments = [
    module.lambda_moneyhub_internal_attachments_owsrequest.policy_arn_output,
    aws_iam_policy.moneyhub_features_secrets_manager_policy.arn,
    aws_iam_policy.sns_statement_attachments_policy.arn,
    aws_iam_policy.moneyhub_attachments_bucket_write_access_policy.arn,
    aws_iam_policy.internal_attachments_dynamo_access_document_policy.arn,
    aws_iam_policy.ses_send_email_policy.arn
  ]
}

module "lambda_moneyhub_internal_attachments_sentry_project" {
  source = "git@github.com:theorchard/terraform-sentry.git//?ref=4.1.2"

  environment        = var.environment
  application_family = var.application_family
  platform           = "python"
  service_name       = var.lambda_internal_attachments_name
  teams              = [var.environment]
}

module "lambda_moneyhub_internal_attachments_owsrequest" {
  source = "git@github.com:theorchard/terraform-owsrequest.git//?ref=1.1.0"

  environment_name = var.environment
  service_name     = var.lambda_internal_attachments_name
}

module "lambda_moneyhub_internal_attachments_secrets" {
  source   = "git@github.com:theorchard/terraform-secrets-manager.git//?ref=1.5.1"
  for_each = toset(var.secrets_manager_secret_names)

  environment                    = var.environment
  service_name                   = var.lambda_internal_attachments_name
  secret_name                    = each.value
  application_family             = var.application_family
  secret_recovery_window_in_days = 7
}

module "internal_attachments_m2m_secrets" {
  source = "git@github.com:theorchard/terraform-secrets-manager.git//modules/auth0m2m?ref=1.6.1"

  environment        = var.environment
  service_name       = var.lambda_internal_attachments_name
  application_family = var.application_family
}

# SES Access
data "aws_ses_email_identity" "sender_domain" {
  email = var.email_sender
}

data "aws_iam_policy_document" "ses_send_email_policy_document" {
  statement {
    effect = "Allow"
    actions = [
      "ses:SendEmail",
      "ses:SendRawEmail"
    ]

    resources = [
      data.aws_ses_email_identity.sender_domain.arn
    ]
  }
}

resource "aws_iam_policy" "ses_send_email_policy" {
  name        = "SES-${var.environment}-internal_attachments_send_email_policy"
  description = "Policy to allow sending emails from SES for internal attachments lambda"
  policy      = data.aws_iam_policy_document.ses_send_email_policy_document.json
}


# Access to SNS topics

data "aws_sns_topic" "sns_statement_atachments_success" {
  name = var.sns_internal_attachments_success_name
}

data "aws_sns_topic" "sns_statement_atachments_fail" {
  name = var.sns_internal_attachments_error_name
}

data "aws_iam_policy_document" "sns_statement_attachments_policy_document" {
  statement {
    actions = [
      "sns:AddPermission",
      "sns:GetEndpointAttributes",
      "sns:ListSubscriptions",
      "sns:ListSubscriptionsByTopic",
      "sns:CheckIfPhoneNumberIsOptedOut",
      "sns:SetTopicAttributes",
      "sns:RemovePermission",
      "sns:SetSubscriptionAttributes",
      "sns:GetPlatformApplicationAttributes",
      "sns:ListPhoneNumbersOptedOut",
      "sns:SetEndpointAttributes",
      "sns:Publish",
      "sns:OptInPhoneNumber",
      "sns:Subscribe",
      "sns:ListEndpointsByPlatformApplication",
      "sns:ConfirmSubscription",
      "sns:SetPlatformApplicationAttributes",
      "sns:GetSubscriptionAttributes",
      "sns:GetTopicAttributes",
      "sns:ListPlatformApplications",
      "sns:GetSMSAttributes",
      "sns:ListTopics",
      "sns:SetSMSAttributes",
      "sns:Unsubscribe"
    ]

    resources = [
      data.aws_sns_topic.sns_statement_atachments_success.arn,
      data.aws_sns_topic.sns_statement_atachments_fail.arn,
    ]
  }
}

resource "aws_iam_policy" "sns_statement_attachments_policy" {
  name        = "SNS-${var.environment}-sns_statement_attachments-${var.lambda_internal_attachments_name}-R"
  description = "Policy to allow read permissions to SNS topic"
  policy      = data.aws_iam_policy_document.sns_statement_attachments_policy_document.json
}

# Trigger Invocation & Subscribe Lambda to SNS topics

resource "aws_lambda_permission" "with_sns" {
  statement_id  = "AllowExecutionFromSNS"
  action        = "lambda:InvokeFunction"
  function_name = module.lambda_moneyhub_internal_attachments.lambda_name
  principal     = "sns.amazonaws.com"
  source_arn    = data.aws_sns_topic.sns_statement_atachments_success.arn
}

resource "aws_sns_topic_subscription" "subscription" {
  topic_arn              = data.aws_sns_topic.sns_statement_atachments_success.arn
  protocol               = "lambda"
  endpoint               = module.lambda_moneyhub_internal_attachments.lambda_arn
  endpoint_auto_confirms = true
}

# Access to DynamoDB

data "aws_dynamodb_table" "statement_attachments_success" {
  name = "${var.environment}_statement_attachments_success"
}

data "aws_iam_policy_document" "internal_attachments_dynamo_access_policy_document" {
  statement {
    resources = [
      data.aws_dynamodb_table.statement_attachments_success.arn,
      "${data.aws_dynamodb_table.statement_attachments_success.arn}/*",
    ]
    actions = [
      "dynamodb:Query",
      "dynamodb:PutItem",
      "dynamodb:ListStreams",
      "dynamodb:BatchWriteItem",
      "dynamodb:DescribeTable",
      "dynamodb:GetShardIterator",
      "dynamodb:UpdateItem",
      "dynamodb:GetRecords",
      "dynamodb:Scan",
      "dynamodb:GetItem",
      "dynamodb:DescribeStream",
      "dynamodb:DescribeLimits",
      "dynamodb:BatchGetItem",
      "dynamodb:DeleteItem",
      "dynamodb:UpdateTable"
    ]
  }
}

resource "aws_iam_policy" "internal_attachments_dynamo_access_document_policy" {
  name        = "S3-${var.environment}-internal_attachments_buckets_rw_access_document_policy"
  description = "Policy for read/write permissions to attachments in Dynamo table"
  policy      = data.aws_iam_policy_document.internal_attachments_dynamo_access_policy_document.json
}


# Write access to attachments bucket

data "aws_s3_bucket" "moneyhub_attachments_bucket" {
  bucket = "${var.environment}-moneyhub-attachments"
}

data "aws_s3_bucket" "moneyhub_custom_reports_bucket" {
  bucket = "${var.environment}-moneyhub-custom-reports"
}

data "aws_s3_bucket" "qa-orcdbucket" {
  bucket = "${var.environment}-orcdbucket"
}

data "aws_iam_policy_document" "moneyhub_attachments_bucket_write_access_document" {
  statement {
    effect = "Allow"
    resources = [
      "${data.aws_s3_bucket.moneyhub_attachments_bucket.arn}/*",
      "${data.aws_s3_bucket.moneyhub_custom_reports_bucket.arn}/*"
    ]
    actions = [
      "s3:CompleteMultipartUpload",
      "s3:PutObject"
    ]
  }

  statement {
    resources = [
      data.aws_s3_bucket.qa-orcdbucket.arn,
      "${data.aws_s3_bucket.qa-orcdbucket.arn}/*"
    ]

    actions = [
      "s3:GetBucketLocation",
      "s3:ListBucket"
    ]
  }

  statement {
    resources = [
      "${data.aws_s3_bucket.qa-orcdbucket.arn}/qa-statement-attachments/",
      "${data.aws_s3_bucket.qa-orcdbucket.arn}/qa-statement-attachments/*",
      "${data.aws_s3_bucket.qa-orcdbucket.arn}/qa-per-label-statement-attachments/",
      "${data.aws_s3_bucket.qa-orcdbucket.arn}/qa-per-label-statement-attachments/*",
    ]
    actions = [
      "s3:DeleteObjectVersion",
      "s3:GetObject",
      "s3:DeleteObject",
      "s3:GetReplicationConfiguration",
      "s3:ListBucket",
      "s3:ListBucketMultipartUploads",
      "s3:GetObjectAcl",
      "s3:GetObjectVersion",
      "s3:GetBucketLocation",
      "s3:GetObjectVersionTorrent",
      "s3:ListMultipartUploadParts",
      "s3:ListBucketVersions",
      "s3:GetLifecycleConfiguration",
      "s3:GetObjectVersionAcl",
      "s3:GetObjectTorrent",
      "s3:GetBucketVersioning",
      "s3:PutObject",
    ]
  }
}

resource "aws_iam_policy" "moneyhub_attachments_bucket_write_access_policy" {
  name        = "S3-${var.environment}-moneyhub-attachments-bucket-write-access-policy"
  description = "Policy for write permissions to attachments and report buckets"
  policy      = data.aws_iam_policy_document.moneyhub_attachments_bucket_write_access_document.json
}

# Access to Split.io API keys

data "aws_iam_policy_document" "moneyhub_features_secrets_manager_policy_document" {
  statement {
    effect = "Allow"
    actions = [
      "secretsmanager:GetSecretValue"
    ]

    resources = [
      "arn:aws:secretsmanager:*:*:secret:qa/python-orchard-features/*",
      "arn:aws:secretsmanager:*:*:secret:qa/python-orchard-features/"
    ]
  }
}

resource "aws_iam_policy" "moneyhub_features_secrets_manager_policy" {
  name        = "SM-${var.environment}-lambda-moneyhub-secrets-manager-policy"
  description = "Permission to get features API key secrets for the moneyhub lambdas"
  policy      = data.aws_iam_policy_document.moneyhub_features_secrets_manager_policy_document.json
}
