# General settings
variable "vpc_id" {
  description = "The ID of the VPC in which to run the elasticsearch domain"
  type        = string
}

variable "subnet_ids" {
  description = "The IDs of the subnets in which to run the elasticsearch domain."
  type        = list(string)
}

variable "env" {
  description = "prod, qa or dev"
  type        = string
  default     = "dev"
}

variable "aws_region" {
  description = "AWS region"
  type        = string
  default     = "us-east-1"
}

variable "aws_es_domain_name" {
  description = "AWS Elasticsearch Domain name, minus environment prefix"
  type        = string
  default     = "ows-elasticsearch"
}

variable "application_family" {
  description = "Application family to which this service belongs"
  type        = string
}

variable "additional_tags" {
  description = "Optional map of additional tags to set on resources. These will be combined with programmatically set required tags."
  type        = map(string)
  default     = {}
}

variable "aws_es_version" {
  description = "AWS Elasticsearch version, or OpenSearch version when use_opensearch_engine is true."
  type        = string
  default     = "7.10"
}

variable "aws_es_instance_type" {
  description = "AWS Elasticsearch instance type, or Search instance for OpenSearch engines."
  type        = string
  default     = "t3.small.elasticsearch"
}

variable "aws_es_instance_count" {
  description = "AWS Elasticsearch instance count"
  type        = number
  default     = 1
}

variable "aws_es_disk_size" {
  description = "AWS Elasticsearch node disk size"
  type        = number
  default     = 10
}

variable "aws_es_disk_type" {
  description = "AWS Elasticsearch EBS volume type"
  type        = string
  default     = "gp2"
}

variable "dedicated_master_count" {
  description = "Number of dedicated master nodes in the cluster"
  type        = number
  default     = 0
}

variable "dedicated_master_type" {
  description = "Instance type of the dedicated master nodes in the cluster"
  type        = string
  default     = "t3.small.elasticsearch"
}

variable "dedicated_master_enabled" {
  description = "Indicates whether dedicated master nodes are enabled for the cluster"
  type        = bool
  default     = false
}

variable "indices_fielddata_cache_size" {
  description = "Amount of memory used for the field data cache can be controlled using indices.fielddata.cache.size."
  type        = number
  default     = 40
}

variable "rest_action_multi_allow_explicit_index" {
  description = "Whether to allow explicit index names in REST multi requests."
  type        = string
  default     = "true"
}

variable "override_main_response_version" {
  description = "Whether to override the main response version."
  type        = string
  default     = "true"
}

# CloudWatch settings.
variable "log_retention_in_days" {
  description = "Amount of days that we store logs for in CloudWatch."
  type        = number
  default     = 365
}

# Datadog settings
variable "datadog_enabled" {
  description = "Whether or not to send Elasticsearch logs to Datadog"
  type        = bool
  default     = false
}

variable "datadog_function_destination_lambda_name" {
  description = "Name of datadog function for shipping cloudwatch logs"
  type        = string
  default     = "DatadogLambdaFunction"
}

variable "datadog_custom_lambda_destination_arn" {
  description = "Custom ARN to use for sending Cloudwatch logs to Datadog. Only needed if overriding the default"
  type        = string
  default     = ""
}

variable "override_route53_zone_id" {
  description = "AWS Route 53 zone id to override the default zone ID"
  type        = string
  default     = null
}

variable "route53_record_creation_enabled" {
  description = "Whether or not to create Route 53 DNS records"
  type        = bool
  default     = true
}

variable "aws_route53_params_type" {
  description = "AWS route 53 parameters type"
  type        = string
  default     = "CNAME"
}

variable "aws_route53_params_ttl" {
  description = "AWS route 53 parameters ttl"
  type        = string
  default     = "120"
}

variable "custom_security_group_ids" {
  description = "Custom security groups for elasticsearch domain. This will override the programmatically generated group"
  type        = list(string)
  default     = []
}

variable "zone_awareness_enabled" {
  description = "Enable zone awareness for Elasticsearch cluster"
  type        = bool
  default     = true
}

# Backup settings
variable "es_cluster_automated_snapshot_start_hour" {
  description = "Amazon ES takes an automated snapshot of your cluster. You can set the start hour for the snapshot"
  type        = number
  default     = 1
}

# Encryption settings
variable "node_to_node_encryption_option" {
  description = "Node-to-node encryption"
  type        = bool
  default     = true
}

variable "use_service_specific_kms_key" {
  description = "Create and use a service-specific KMS key to encrypt the Elasticsearch domain. If not specified the aws/es service KMS key will be used."
  type        = bool
  default     = false
}

variable "encrypt_at_rest_enabled" {
  description = "Whether to enable encryption at rest"
  type        = bool
  default     = true
}

# Log publishing settings
variable "log_publishing_options" {
  default = []
  type = list(object({
    enabled  = bool
    log_type = string
  }))
  validation {
    condition = var.advanced_security_options_enabled == false ? length([
      for x in var.log_publishing_options : true if x.enabled && x.log_type == "AUDIT_LOGS"
    ]) == 0 : true
    error_message = "AUDIT_LOGS log publishing cannot be enabled without enabling advanced_security_options."
  }
}

# Security and access settings (FGAC)
variable "advanced_security_options_enabled" {
  description = "Whether or not fine-grained access controls are enabled. Not applicable for T2 instance types."
  type        = bool
  default     = false
}

variable "advanced_security_options_internal_user_database_enabled" {
  description = "Whether or not the Internal User Database is enabled. Only applicable when var.advanced_security_options_enabled is true."
  type        = bool
  default     = false
}

variable "advanced_security_options_internal_master_user_name" {
  description = "Optional master user name when utilizing internal user database. This will override the auto-generated random user. Only applicable when var.advanced_security_options_internal_user_database_enabled is true"
  type        = string
  default     = ""
}

variable "advanced_security_options_internal_master_user_password" {
  description = "Optional master user password when utilizing internal user database. This will override the auto-generated random password. Only applicable when var.advanced_security_options_internal_user_database_enabled is true"
  type        = string
  default     = ""
}

variable "advanced_security_options_iam_master_user_arn" {
  description = "IAM Master User ARN, this only applies when var.advanced_security_options_enabled is true and var.advanced_security_options_internal_user_database_enabled is false."
  type        = string
  default     = ""

  validation {
    condition     = can(regex("^arn:aws:iam::[0-9]{12}:(user|role)/.*", var.advanced_security_options_iam_master_user_arn)) || var.advanced_security_options_iam_master_user_arn == ""
    error_message = "The IAM Master User ARN must be a valid IAM user or role ARN."
  }

  validation {
    condition     = var.advanced_security_options_iam_master_user_arn != "" ? (var.advanced_security_options_enabled && !var.advanced_security_options_internal_user_database_enabled) : true
    error_message = "When using an IAM Master User, advanced_security_options_enabled should be true and advanced_security_options_internal_user_database_enabled should be false."
  }
}


# HTTPS settings
variable "tls_security_policy" {
  description = "Name of TLS security policy to apply to the HTTPS endpoint"
  type        = string
  default     = "Policy-Min-TLS-1-2-2019-07"
}

variable "allow_access_from_vpc_private_subnets" {
  description = "Whether to allow access from VPC private subnets"
  type        = bool
  default     = true
}

variable "dev_https_allowed_custom_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTPS for dev environments"
  type        = list(string)
  default     = []
}

variable "qa_https_allowed_custom_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTPS for QA environments"
  type        = list(string)
  default     = []
}

variable "prod_https_allowed_custom_cidr_blocks" {
  description = "CIDR blocks from which to allow HTTPS for prod environments"
  type        = list(string)
  default     = []
}

variable "https_allowed_custom_prefix_list_names" {
  description = "Prefix lists names from which to allow HTTPS"
  type        = list(string)

  default = [
    "shared-orcd-atlantis-private-subnet-prefix-list",
  ]
}

# Ultrawarm settings
variable "warm_enabled" {
  description = "Whether or not ultrawarm is enabled. Not applicable for T2 or T3 instance types."
  type        = bool
  default     = false
}

variable "warm_count" {
  description = "Number of ultrawarm nodes"
  type        = number
  default     = null
}

variable "warm_type" {
  description = "Instance type for ultrawarm nodes, e.g. ultrawarm1.medium.elasticsearch. Only set when warm_enabled is true"
  type        = string
  default     = null
}

# Use OpenSearch engine or old ElasticSearch engines
variable "use_opensearch_engine" {
  description = "Flag to configure the domain to be set up using an OpenSearch engine instead of the ElasticSearch ones."
  type        = bool
  default     = false
}

locals {
  https_allowed_custom_cidr_blocks = {
    dev    = var.dev_https_allowed_custom_cidr_blocks
    qa     = var.qa_https_allowed_custom_cidr_blocks,
    prod   = var.prod_https_allowed_custom_cidr_blocks,
    shared = var.prod_https_allowed_custom_cidr_blocks,

    # Determine Route53 zone ID based on environment unless overridden
  }

  https_allowed_prefix_list_names = concat(
    lookup({
      dev = [
        "vpn-ny-users"
      ]
      qa = [
        "vpn-ny-users"
      ]
    }, var.env, []),
    var.https_allowed_custom_prefix_list_names,
    var.allow_access_from_vpc_private_subnets ? [data.aws_ec2_managed_prefix_list.private_subnets.name] : []
  )

  combined_resource_tags = merge(
    {
      environment        = var.env
      service_name       = var.aws_es_domain_name
      application_family = var.application_family
      terraformed        = true
      Domain             = "${var.env}-${var.aws_es_domain_name}"
    },
    var.additional_tags
  )

  es_arn_output         = var.use_opensearch_engine ? aws_opensearch_domain.default[0].arn : aws_elasticsearch_domain.default[0].arn
  es_domain_name_output = var.use_opensearch_engine ? aws_opensearch_domain.default[0].domain_name : aws_elasticsearch_domain.default[0].domain_name
  es_endpoint_output    = var.use_opensearch_engine ? aws_opensearch_domain.default[0].endpoint : aws_elasticsearch_domain.default[0].endpoint

  datadog_function_destination_arn = var.datadog_custom_lambda_destination_arn != "" ? var.datadog_custom_lambda_destination_arn : "arn:aws:lambda:${var.aws_region}:${data.aws_caller_identity.current.account_id}:function:${var.datadog_function_destination_lambda_name}"

  can_use_graviton = var.use_opensearch_engine || can(regex("^(7\\.(9|[1-9][0-9])|[89]\\.|[1-9][0-9]+\\.)", var.aws_es_version))

  primsa_sg_exception_tags = {
    "eiso-exception" = "aws.08.30"
  }

  default_log_publishing_options = [
    {
      enabled  = true
      log_type = "INDEX_SLOW_LOGS"
    },
    {
      enabled  = true
      log_type = "SEARCH_SLOW_LOGS"
    },
    {
      enabled  = true
      log_type = "ES_APPLICATION_LOGS"
    },
    {
      enabled  = true
      log_type = "AUDIT_LOGS"
    },
  ]
  log_publishing_options = var.advanced_security_options_enabled ? (
    length(var.log_publishing_options) > 0 ? var.log_publishing_options : local.default_log_publishing_options
  ) : var.log_publishing_options

  route53_zone_id = var.override_route53_zone_id != null ? var.override_route53_zone_id : (var.env == "dev" ? "Z21XEY26C989RH" : "Z0183645HDT0XCWHLW7S")
}

# Not real outputs - only used to validate and enforce graviton instance type where appropriate.
output "validate_graviton_instance_type" {
  value = null

  precondition {
    condition     = local.can_use_graviton ? can(regex("^(t3.*|[^.]*g[^.]*\\..*)$", var.aws_es_instance_type)) : true
    error_message = "Graviton-based instance types are recommended for this OpenSearch. Please choose a Graviton instance type or a supported t3 instance type."
  }
}

output "validate_dedicated_instance" {
  value = null

  precondition {
    condition     = local.can_use_graviton ? can(regex("^(t3.*|[^.]*g[^.]*\\..*)$", var.dedicated_master_type)) : true
    error_message = "Graviton-based instance types are recommended for dedicated master nodes. Please choose a Graviton instance type or a supported t3 instance type."
  }
}
