module "default_tags" {
  source             = "git@github.com:theorchard/terraform-default-tags.git//?ref=2.1.0"
  environment        = var.environment
  application_family = var.application_family
  service_name       = var.service_name
  team_name          = var.team_name
}

provider "aws" {
  region = var.region

  default_tags {
    tags = module.default_tags.tags
  }
}

terraform {
  backend "s3" {
    bucket  = "orcd-terraform-state"
    key     = "prod/neighbouring-rights/ingestion/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

data "aws_s3_bucket" "s3_bucket" {
  bucket = "${var.environment}-neighbouring-rights"
}

data "aws_iam_policy" "ingestion_bucket_rw_policy" {
  name = "S3-${var.environment}-neighbouring-rights-ingestion-RW"
}

// The contribution creation Lambda
module "lambda_nr_ingest_contributor" {
  source                      = "git@github.com:theorchard/terraform-lambda.git?ref=4.3.0"
  environment                 = var.environment
  lambda_name                 = var.contributor_lambda_name
  lambda_description          = "Creates and Update metadata in Neo4j and creates success or failure reports"
  lambda_function_timeout     = "300"
  use_container_image         = true
  vpc_subnet_ids              = var.vpc_subnet_ids
  vpc_enabled                 = true
  vpc_id                      = var.vpc_id
  datadog_advanced_enabled    = true
  application_family          = var.application_family
  lambda_function_memory_size = 512

  lambda_function_environment_variables = {
    Environment                = var.environment
    DD_LAMBDA_HANDLER          = "app.handler"
    SENTRY_DSN                 = module.lambda_nr_ingest_contributor_sentry_project.sentry_key_dsn_public_output
    KAFKA_BROKERS              = var.kafka_brokers
    KAFKA_FILE_INGESTION_TOPIC = var.kafka_file_ingestion_topic
    SCHEMA_REGISTRY_URL        = var.schema_registry_url
    GRAPHQL_URL                = var.graphql_router_url
    BUCKET_NAME                = data.aws_s3_bucket.s3_bucket.bucket
  }

  lambda_function_reserved_concurrent_executions = 30

  iam_managed_policy_attachments = [
    data.aws_iam_policy.ingestion_bucket_rw_policy.arn
  ]
}

// Sentry project for the lambda
module "lambda_nr_ingest_contributor_sentry_project" {
  source             = "git@github.com:theorchard/terraform-sentry//?ref=4.1.2"
  service_name       = var.contributor_lambda_name
  environment        = var.environment
  platform           = "node"
  application_family = var.application_family
}

// Datadog monitors for the lambda errors and invocation errors
module "datadog_lambda_dashboards_and_monitors" {
  source                 = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.13.9"
  service_name           = var.contributor_lambda_name
  environment            = var.environment
  notification_endpoints = var.notification_endpoints
  teams                  = [var.team_name]
}

// The validate Lambda
module "lambda_nr_ingest_validate" {
  source                      = "git@github.com:theorchard/terraform-lambda.git?ref=4.3.0"
  environment                 = var.environment
  lambda_name                 = var.validate_lambda_name
  lambda_description          = "Lambda that validates and splits bulk contributions csv."
  lambda_function_timeout     = "900"
  use_container_image         = true
  vpc_subnet_ids              = var.vpc_subnet_ids
  vpc_enabled                 = true
  vpc_id                      = var.vpc_id
  datadog_advanced_enabled    = true
  application_family          = var.application_family
  lambda_function_memory_size = var.lambda_memory_size

  lambda_function_environment_variables = {
    Environment                = var.environment
    DD_LAMBDA_HANDLER          = "app.handler"
    SENTRY_DSN                 = module.lambda_nr_ingest_validate_sentry_project.sentry_key_dsn_public_output
    KAFKA_BROKERS              = var.kafka_brokers
    KAFKA_FILE_INGESTION_TOPIC = var.kafka_file_ingestion_topic
    SCHEMA_REGISTRY_URL        = var.schema_registry_url

  }

  lambda_function_reserved_concurrent_executions = 10

  iam_managed_policy_attachments = [
    data.aws_iam_policy.ingestion_bucket_rw_policy.arn
  ]
}

// Sentry project for the validate lambda
module "lambda_nr_ingest_validate_sentry_project" {
  source             = "git@github.com:theorchard/terraform-sentry//?ref=4.1.2"
  service_name       = var.validate_lambda_name
  environment        = var.environment
  platform           = "node"
  application_family = var.application_family
}

// Datadog monitors for the validate lambda errors and invocation errors
module "datadog_lambda_nr_ingest_validate_dashboards" {
  source                 = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.13.9"
  service_name           = var.validate_lambda_name
  environment            = var.environment
  notification_endpoints = var.notification_endpoints
  teams                  = [var.team_name]
}

// The report Lambda
module "lambda_nr_ingest_report" {
  source                                         = "git@github.com:theorchard/terraform-lambda.git?ref=4.3.0"
  environment                                    = var.environment
  lambda_name                                    = var.report_lambda_name
  lambda_description                             = "Lambda that generate final report csv files."
  lambda_function_timeout                        = "300"
  use_container_image                            = true
  vpc_subnet_ids                                 = var.vpc_subnet_ids
  vpc_enabled                                    = true
  vpc_id                                         = var.vpc_id
  datadog_advanced_enabled                       = true
  application_family                             = var.application_family
  lambda_function_reserved_concurrent_executions = 10
  lambda_function_memory_size                    = 512

  lambda_function_environment_variables = {
    Environment                = var.environment
    DD_LAMBDA_HANDLER          = "app.handler"
    SENTRY_DSN                 = module.lambda_nr_ingest_report_sentry_project.sentry_key_dsn_public_output
    BUCKET_NAME                = data.aws_s3_bucket.s3_bucket.bucket
    KAFKA_BROKERS              = var.kafka_brokers
    KAFKA_FILE_INGESTION_TOPIC = var.kafka_file_ingestion_topic
    SCHEMA_REGISTRY_URL        = var.schema_registry_url

  }

  iam_managed_policy_attachments = [
    data.aws_iam_policy.ingestion_bucket_rw_policy.arn
  ]
}

// Sentry project for the report lambda
module "lambda_nr_ingest_report_sentry_project" {
  source             = "git@github.com:theorchard/terraform-sentry//?ref=4.1.2"
  service_name       = var.report_lambda_name
  environment        = var.environment
  platform           = "node"
  application_family = var.application_family
}

// Datadog monitors for the report lambda errors and invocation errors
module "datadog_lambda_nr_ingest_report_dashboards" {
  source                 = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.13.9"
  service_name           = var.report_lambda_name
  environment            = var.environment
  notification_endpoints = var.notification_endpoints
  teams                  = [var.team_name]
}


// The contribution add version Lambda
module "lambda_nr_contribution_add_version" {
  source                                         = "git@github.com:theorchard/terraform-lambda.git?ref=4.3.0"
  environment                                    = var.environment
  lambda_name                                    = var.contribution_add_version_name
  lambda_description                             = "Lambda that adds versions of contributions on S3."
  lambda_function_timeout                        = "300"
  use_container_image                            = true
  vpc_subnet_ids                                 = var.vpc_subnet_ids
  vpc_enabled                                    = true
  vpc_id                                         = var.vpc_id
  datadog_advanced_enabled                       = true
  application_family                             = var.application_family
  lambda_function_reserved_concurrent_executions = 3
  lambda_function_memory_size                    = 512

  lambda_function_environment_variables = {
    Environment                     = var.environment
    DD_LAMBDA_HANDLER               = "app.handler"
    SENTRY_DSN                      = module.lambda_nr_contribution_add_version_sentry_project.sentry_key_dsn_public_output
    BUCKET_NAME                     = data.aws_s3_bucket.s3_bucket.bucket
    KAFKA_BROKERS                   = var.kafka_brokers
    KAFKA_TOPIC                     = var.contribution_version_topic
    GRAPHQL_URL                     = var.graphql_router_url
    KAFKAJS_NO_PARTITIONER_WARNING  = 1
  }

  iam_managed_policy_attachments = [
    data.aws_iam_policy.ingestion_bucket_rw_policy.arn
  ]

  msk_event_enabled                      = true
  event_source_mapping_msk_cluster_name  = var.trigger_msk_cluster_name
  event_source_mapping_msk_cluster_uuid  = var.trigger_msk_cluster_uuid
  event_source_mapping_batch_size        = 1
  kafka_topics = [var.contribution_metadata_topic]
  event_source_mapping_starting_position = "LATEST"
}

resource "aws_lambda_function_event_invoke_config" "lambda_nr_contribution_add_version_invoke_config" {
  function_name                = module.lambda_nr_contribution_add_version.lambda_name
  maximum_event_age_in_seconds = 21600
  maximum_retry_attempts       = 0
}


// Sentry project for the contribution add version lambda
module "lambda_nr_contribution_add_version_sentry_project" {
  source             = "git@github.com:theorchard/terraform-sentry//?ref=4.1.2"
  service_name       = var.contribution_add_version_name
  environment        = var.environment
  platform           = "node"
  application_family = var.application_family
}

// Datadog monitors for the contribution add version lambda errors and invocation errors
module "datadog_lambda_nr_contribution_add_version_dashboards" {
  source                 = "git@github.com:theorchard/terraform-datadog.git//modules/lambda?ref=6.13.9"
  service_name           = var.contribution_add_version_name
  environment            = var.environment
  notification_endpoints = var.notification_endpoints
  teams                  = [var.team_name]
}

# CloudWatch Events rule role for starting execution.
resource "aws_iam_role" "execute_state_machine_role" {
  name               = "${var.environment}-nr-bulk-ingestion-execute-state-machine"
  assume_role_policy = data.aws_iam_policy_document.assume_role_for_events_policy.json
}

data "aws_iam_policy_document" "assume_role_for_events_policy" {
  statement {
    sid     = "AllowCWEServiceToAssumeRole"
    effect  = "Allow"
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["events.amazonaws.com"]
    }
  }
}

# Policy for starting execution initiated by a CloudWatch Events rule.
data "aws_iam_policy_document" "start_execution_policy" {
  statement {
    effect    = "Allow"
    actions   = ["states:StartExecution"]
    resources = [aws_sfn_state_machine.state_machine.id]
  }
}

resource "aws_iam_role_policy" "start_execution_role_policy" {
  name   = "${var.environment}-nr-bulk-ingestion-execute-state-machine"
  role   = aws_iam_role.execute_state_machine_role.id
  policy = data.aws_iam_policy_document.start_execution_policy.json
}

# Enable S3 notifications for a bucket.
resource "aws_s3_bucket_notification" "bucket_notification" {
  bucket      = data.aws_s3_bucket.s3_bucket.bucket
  eventbridge = true
}

# CloudWatch Event rule and target.
resource "aws_cloudwatch_event_rule" "input_asset_event_rule" {
  name        = "${var.environment}-nr-bulk-ingestion-input-rule"
  description = "The CloudWatch event rule for put object events on neighbouring-rights bucket"

  event_pattern = jsonencode(
    {
      source      = ["aws.s3"],
      detail-type = ["Object Created"],
      detail = {
        bucket = {
          name = [data.aws_s3_bucket.s3_bucket.bucket]
        },
        object : {
          key : [{ prefix : "ingestion/uploads" }]
        }
      }
    }
  )

  role_arn = aws_iam_role.execute_state_machine_role.arn

  tags = {
    service_name       = "${var.environment}-eventbridge-s3-nr"
    environment        = var.environment
    application_family = var.application_family
    terraformed        = true
  }
}

resource "aws_cloudwatch_event_target" "state_machine_target" {
  target_id = "${var.environment}_state_machine_target_rule_target"
  rule      = aws_cloudwatch_event_rule.input_asset_event_rule.name
  arn       = aws_sfn_state_machine.state_machine.id
  role_arn  = aws_iam_role.execute_state_machine_role.arn
}

# NR bulk ingestion state machine.

# Policy for lambda invocation initiated by state machine.
data "aws_iam_policy_document" "assume_role_for_state_machine_policy" {
  statement {
    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type = "Service"

      identifiers = [
        "states.${var.region}.amazonaws.com",
      ]
    }
  }
}

# States role for lambda invocation
resource "aws_iam_role" "invoke_lambdas_role_for_state_machine" {
  name               = "${var.environment}-nr-bulk-ingestion-invoke-lambdas-role"
  assume_role_policy = data.aws_iam_policy_document.assume_role_for_state_machine_policy.json
}


data "aws_iam_policy_document" "invoke_lambda_policy_for_state_machine" {
  statement {
    actions = [
      "lambda:InvokeFunction",
    ]
    resources = [
      var.av_scan_lambda_arn,
      module.lambda_nr_ingest_contributor.lambda_arn,
      module.lambda_nr_ingest_validate.lambda_arn,
      module.lambda_nr_ingest_report.lambda_arn,
    ]
  }
}


# Policy that gives the state machine role permission to invoke lambdas
resource "aws_iam_role_policy" "invoke_lambda_role_policy" {
  name   = "${var.environment}-nr-bulk-ingestion-invoke-lambda-role-policy"
  role   = aws_iam_role.invoke_lambdas_role_for_state_machine.id
  policy = data.aws_iam_policy_document.invoke_lambda_policy_for_state_machine.json
}

data "template_file" "state_machine_definition" {
  template = file("${path.module}/bulk_ingestion_workflow.json")

  vars = {
    # add all lambda variables here that will be used by bulk_ingestion_workflow.json.
    contributor_lambda_arn = module.lambda_nr_ingest_contributor.lambda_arn
    av_scan_lambda_arn     = var.av_scan_lambda_arn
    validate_lambda_arn    = module.lambda_nr_ingest_validate.lambda_arn
    report_lambda_arn      = module.lambda_nr_ingest_report.lambda_arn
  }
}

resource "aws_sfn_state_machine" "state_machine" {
  name       = "${var.environment}-${var.state_machine_name}"
  role_arn   = aws_iam_role.invoke_lambdas_role_for_state_machine.arn
  definition = data.template_file.state_machine_definition.rendered

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

  tracing_configuration {
    enabled = true
  }
}

variable "lambda_function_names" {
  description = "List of lambda-nr fns"
  type        = list(string)
  default = [
    "lambda-nr-ingest-contributor",
  ]
}

module "m2m_secrets" {
  source             = "git@github.com:theorchard/terraform-secrets-manager.git//modules/auth0m2m?ref=1.6.1"
  for_each           = toset(var.lambda_function_names)
  environment        = var.environment
  service_name       = each.value
  application_family = var.application_family
}
