# General variables
variable "environment" {
  description = "Name of the environment, e.g. dev, qa, prod"
  default     = "dev"
}

variable "service_name" {
  description = "Service name, without environment prefix"
  default     = "neo4j-service"
}

variable "teams" {
  type        = set(string)
  description = "A set of Datadog Teams to associate the resources with"
  default     = []
}

# AWS variables
variable "aws_region" {
  description = "AWS region from which to pull metrics"
  default     = "us-east-1"
}

# Alert variables
variable "notification_endpoints" {
  description = "Endpoints for alerts. Can be email, slack, pagerduty, etc"
  default     = "@slack-monitoring @slack-neo4j-db"
}

variable "escalation_notification_endpoints" {
  description = "Endpoints for escalation alerts. Can be email, slack, pagerduty, etc"
  default     = "@slack-monitoring @slack-neo4j-db"
}

variable "neo4j_monitors_enabled" {
  description = "Whether to enable all Datadog Neo4j monitors. Set to false to disable all monitors in this module."
  type        = bool
  default     = true
}

# Memory variables
variable "memory_critical_number" {
  description = "Memory utilization percentage (per 5m) for critical status"
  default     = 95
}

variable "memory_critical_recovery_number" {
  description = "Memory utilization percentage (per 5m) for critical recovery"
  default     = 94
}

variable "memory_warning_number" {
  description = "Memory utilization percentage (per 5m) for warnings"
  default     = 91
}

variable "memory_warning_recovery_number" {
  description = "Memory utilization percentage (per 5m) for warning recovery"
  default     = 90
}

variable "low_memory_critical_number" {
  description = "Memory utilization percentage (per 5m) for critical status"
  default     = 30
}

variable "low_memory_critical_recovery_number" {
  description = "Memory utilization percentage (per 5m) for critical recovery"
  default     = 40
}

variable "low_memory_warning_number" {
  description = "Memory utilization percentage (per 5m) for warnings"
  default     = 45
}

variable "low_memory_warning_recovery_number" {
  description = "Memory utilization percentage (per 5m) for warning recovery"
  default     = 50
}

# CPU variables
variable "cpu_critical_number" {
  description = "CPU utilization percentage (per 5m) for critical status"
  default     = 90
}

variable "cpu_critical_recovery_number" {
  description = "CPU utilization percentage (per 5m) for critical recovery"
  default     = 85
}

variable "cpu_warning_number" {
  description = "CPU utilization percentage (per 5m) for warnings"
  default     = 80
}

variable "cpu_warning_recovery_number" {
  description = "CPU utilization percentage (per 5m) for warning recovery"
  default     = 75
}

# Disk Space variables
variable "disk_space_critical_number" {
  description = "disk_space utilization percentage (per 5m) for critical status"
  default     = 90
}

variable "disk_space_critical_recovery_number" {
  description = "disk_space utilization percentage (per 5m) for critical recovery"
  default     = 85
}

variable "disk_space_warning_number" {
  description = "disk_space utilization percentage (per 5m) for warnings"
  default     = 80
}

variable "disk_space_warning_recovery_number" {
  description = "disk_space utilization percentage (per 5m) for warning recovery"
  default     = 75
}

variable "disk_space_evaluation_window" {
  description = "The time window over which to evaluate disk space usage"
  default     = "last_5m"
}

# neo4j_cypher_transaction_max_size_exceeded variables
variable "number_of_failed_queries_critical" {
  description = "Number of cyphers exceeded dbms.memory.transaction.max_size for critical status"
  default     = 5
}

variable "number_of_failed_queries_warning" {
  description = "Number of cyphers exceeded dbms.memory.transaction.max_size for warnings"
  default     = 2
}


variable "default_database_name" {
  description = "Default database name used in neo4j 4.x"
  default     = "graph.db"
}

# Version dependant variables/locals
variable "neo4j_major_version_number" {
  description = "Major version number of Neo4j (3 or 4 or 5)"
  default     = 3
}

variable "dependent_applications" {
  type        = set(string)
  description = "Optional list of dependent applications to set as a dependent_application tag on resources. These will be combined with programmatically set required tags."
  default     = []
}

locals {
  # @todo check why we dont get neo4j.openmetrics.health for V5
  neo4j_dd_service_check_name = var.neo4j_major_version_number == 3 ? "neo4j.can_connect" : "neo4j.openmetrics.health"

  v3x_metrics = [
    "neo4j.bytes.written",
    "neo4j.property.ids.inuse",
    "neo4j.page.cache.file.unmappings",
    "neo4j.node.ids.inuse",
    "neo4j.peak.rolledback.transactions",
    "neo4j.store.log.version",
    "neo4j.open.transactions",
    "neo4j.adverted.locks",
    "neo4j.bytes.written",
    "neo4j.kernel.starttime",
    "neo4j.page.cache.file.mappings",
    "neo4j.bytes.read",
    "neo4j.committed.transactions",
    "neo4j.string.store.size",
    "neo4j.relationship.ids.inuse",
    "neo4j.peak.concurrent.transactions",
    "neo4j.page.cache.flushes",
    "neo4j.page.cache.faults",
    "neo4j.page.cache.eviction.exceptions",
    "neo4j.logicallog.size",
    "neo4j.relationship.store.size",
    "neo4j.total.store.size",
    "neo4j.page.cache.evictions",
    "neo4j.opened.transactions",
    "neo4j.array.store.size",
    "neo4j.page.cache.pins",
    "neo4j.store.creationdate",
    "neo4j.last.committed.transaction.id",
    "neo4j.relationshiptype.ids.inuse",
    "neo4j.node.store.size",
  ]

  # Neo4j Metrics (https://github.com/DataDog/integrations-extras/blob/master/neo4j/metadata.csv)
  # Missing from 3.x to 4.x integration:
  # - neo4j.bytes.written
  # - neo4j.page.cache.fileunmappings
  # - neo4j.store.log.version
  # - neo4j.adverted.locks (or neo4j.averteddeadlocks)
  # - neo4j.kernel.starttime
  # - neo4j.page.cache.file.mappings
  # - neo4j.string.store.size
  # - neo4j.logicallog.size
  # - neo4j.relationship.store.size
  # - neo4j.opened.transactions
  # - neo4j.array.store.size
  # - neo4j.store.creationdate

  v4x_metrics = [
    "neo4j.check_point_duration",
    "neo4j.check_point_events.count",
    "neo4j.db_query_execution_failure.count",
    "neo4j.ids_in_use_node",
    "neo4j.ids_in_use_property",
    "neo4j.ids_in_use_relationship",
    "neo4j.ids_in_use_relationship_type",
    "neo4j.pool.transaction.total_used",
    "neo4j.pool.transaction.used_native",
    "neo4j.pool.transaction.used_heap",
    "neo4j.store_size_database",
    "neo4j.store_size_total",
    "neo4j.transaction_active_read",
    "neo4j.transaction_active_write",
    "neo4j.bolt.connections_running",
    "neo4j.dbms.pool.bolt.used_heap",
    "neo4j.dbms.pool.bolt.total_used",
    "neo4j.dbms.pool.bolt.total_size",
    "neo4j.dbms.pool.bolt.free",
    "neo4j.causal_clustering_core_is_leader",
    "neo4j.cypher_replan_events.count",
    "neo4j.page_cache.hit_ratio",
    "neo4j.page_cache.hits.count",
    "neo4j.page_cache.page_faults.count",
    "neo4j.page_cache.usage_ratio",
    "neo4j.vm.heap.used",
    "neo4j.vm.thread.count",
    "neo4j.vm.thread.total",
  ]

  v5x_metrics = [
    # Bolt metrics
    "neo4j.bolt.connections_opened.count",
    "neo4j.bolt.connections_closed.count",
    "neo4j.bolt.connections_running",
    "neo4j.bolt.connections_idle",
    "neo4j.bolt.messages_received.count",
    "neo4j.bolt.messages_started.count",
    "neo4j.bolt.messages_done.count",
    "neo4j.bolt.messages_failed.count",
    "neo4j.bolt.accumulated_queue_time.count",
    "neo4j.bolt.accumulated_processing_time.count",
    # Bolt Driver metrics
    "neo4j.bolt_driver_api_managed_transaction_function_calls.count",
    "neo4j.bolt_driver_api_execute_calls.count",
    # Database checkpointing metrics
    "neo4j.check_point_events.count",
    "neo4j.check_point_total_time.count",
    "neo4j.check_point_duration",
    "neo4j.check_point_pages_flushed",
    "neo4j.check_point_io_performed",
    "neo4j.check_point_io_limit",
    # Cypher metrics
    "neo4j.cypher_replan_events.count",
    "neo4j.cypher_replan_wait_time.count",
    # Database data count metrics
    "neo4j.neo4j_count_relationship",
    "neo4j.neo4j_count_node",
    "neo4j.neo4j_count_relationship_types",
    # Database neo4j pools metrics with cluster pool
    "neo4j.pool.cluster.used_heap",
    "neo4j.pool.cluster.used_native",
    "neo4j.pool.cluster.total_used",
    "neo4j.pool.cluster.total_size",
    "neo4j.pool.cluster_free",
    # Database operation count metrics
    "neo4j.db.operation.count.create.count",
    "neo4j.db.operation.count.start.count",
    "neo4j.db.operation.count.stop.count",
    "neo4j.db.operation.count.drop.count",
    "neo4j.db.operation.count.failed.count",
    "neo4j.db.operation.count.recovered.count",
    # Database state count metrics - none of these are reported as of now
    # "neo4j.db.state.count.hosted",
    # "neo4j.db.state.count.failed",
    # "neo4j.db.state.count.desired_started",
    # Global neo4j pools metrics
    "neo4j.dbms.pool.bolt.used_heap",
    "neo4j.dbms.pool.bolt.total_used",
    "neo4j.dbms.pool.bolt.total_size",
    "neo4j.dbms.pool.bolt.free",
    # Database page cache metrics
    "neo4j.page_cache.eviction_exceptions.count",
    "neo4j.page_cache.flushes.count",
    "neo4j.page_cache.merges.count",
    "neo4j.page_cache.unpins.count",
    "neo4j.page_cache.pins.count",
    "neo4j.page_cache.evictions.count",
    "neo4j.page_cache.evictions_cooperative.count",
    "neo4j.page_cache.flushes.count",
    "neo4j.page_cache.page_faults.count",
    "neo4j.page_cache.page_fault_failures.count",
    "neo4j.page_cache.hits.count",
    "neo4j.page_cache.hit_ratio",
    "neo4j.page_cache.usage_ratio",
    "neo4j.page_cache.bytes_read.count",
    "neo4j.page_cache.bytes_written.count",
    "neo4j.page_cache.throttled_times.count",
    "neo4j.page_cache.throttled_millis.count",
    "neo4j.page_cache.pages_copied.count",
    # Query execution metrics
    "neo4j.db_query_execution_success.count",
    "neo4j.db_query_execution_failure.count",
    "neo4j.db_query_execution_latency_millis.count",
    "neo4j.db_query_execution_latency_millis.quantile",
    # Query routing metrics
    "neo4j.routing.query.count.local.count",
    "neo4j.routing.query.count.remote_internal.count",
    "neo4j.routing.query.count.remote_external.count",
    # Database store size metrics
    "neo4j.store_size_total",
    "neo4j.store_size_database",
    # Database transaction log metrics
    "neo4j.log_rotation_events.count",
    "neo4j.log_rotation_total_time.count",
    "neo4j.log_rotation_duration",
    "neo4j.log_appended_bytes.count",
    "neo4j.log_flushes.count",
    "neo4j.log_append_batch_size",
    # Database transaction metrics
    "neo4j.transaction_started.count",
    "neo4j.transaction_peak_concurrent.count",
    "neo4j.transaction_active",
    "neo4j.transaction_active_read",
    "neo4j.transaction_active_write",
    "neo4j.transaction_committed.count",
    "neo4j.transaction_committed_read.count",
    "neo4j.transaction_committed_write.count",
    "neo4j.transaction_rollbacks.count",
    "neo4j.transaction_rollbacks_read.count",
    "neo4j.transaction_rollbacks_write.count",
    "neo4j.transaction_terminated.count",
    "neo4j.transaction_terminated_read.count",
    "neo4j.transaction_terminated_write.count",
    "neo4j.transaction_last_committed_tx_id.count",
    "neo4j.transaction_last_closed_tx_id.count",
    "neo4j.transaction_tx_size_heap.count",
    "neo4j.transaction_tx_size_native.count",
    # Database index metrics - none of these are reported as of now
    # "neo4j.index.fulltext.queried",
    # "neo4j.index.fulltext.populated",
    # "neo4j.index.lookup.queried",
    # "neo4j.index.lookup.populated",
    # "neo4j.index.text.queried",
    # "neo4j.index.text.populated",
    # "neo4j.index.range.queried",
    # "neo4j.index.range.populated",
    # "neo4j.index.point.queried",
    # "neo4j.index.point.populated",
    # "neo4j.index.vector.queried",
    # "neo4j.index.vector.populated",
    # Server metrics
    "neo4j.server.threads.jetty.idle",
    "neo4j.server.threads.jetty.all",
    # Catch-up metrics
    "neo4j.cluster_catchup_tx_pull_requests_received.count",
    # Discovery metrics v2
    "neo4j.cluster.discovery_cluster_members",
    "neo4j.cluster.discovery_cluster_converged",
    "neo4j.cluster.discovery_cluster_unreachable",
    "neo4j.dbms.cluster.discovery.memberset.reachable",
    # Raft metrics
    "neo4j.cluster_raft_append_index",
    "neo4j.cluster_raft_commit_index",
    "neo4j.cluster_raft_applied_index",
    "neo4j.cluster_raft_term",
    "neo4j.cluster_raft_tx_retries.count",
    "neo4j.cluster_raft_is_leader",
    "neo4j.cluster_raft_in_flight_cache_total_bytes",
    "neo4j.cluster_raft_in_flight_cache_max_bytes",
    "neo4j.cluster_raft_in_flight_cache_element_count",
    "neo4j.cluster_raft_in_flight_cache_max_elements",
    "neo4j.cluster_raft_in_flight_cache_hits",
    "neo4j.cluster_raft_in_flight_cache_misses",
    "neo4j.cluster_raft_raft_log_entry_prefetch_buffer_lag",
    "neo4j.cluster_raft_raft_log_entry_prefetch_buffer_bytes",
    "neo4j.cluster_raft_raft_log_entry_prefetch_buffer_size",
    "neo4j.cluster_raft_raft_log_entry_prefetch_buffer_sync_put",
    "neo4j.cluster_raft_raft_log_entry_prefetch_buffer_sync_put",
    "neo4j.cluster_raft_message_processing_delay",
    "neo4j.cluster_raft_message_processing_timer.count",
    "neo4j.cluster_raft_replication_new.count",
    "neo4j.cluster_raft_replication_attempt.count",
    "neo4j.cluster_raft_replication_fail.count",
    "neo4j.cluster_raft_replication_maybe.count",
    "neo4j.cluster_raft_replication_success.count",
    "neo4j.cluster_raft_last_leader_message",
    "neo4j.database.graph.db.cluster.raft.is_leader",
    "neo4j.database.system.cluster.raft.is_leader",
    # Store copy metrics - none of these are reported as of now
    # "neo4j.cluster.store_copy.pull_updates",
    # "neo4j.cluster.store_copy.pull_update_highest_tx_id_requested",
    # "neo4j.cluster.store_copy.pull_update_highest_tx_id_received",
    # JVM file descriptor metrics
    "neo4j.vm.file.descriptors.count",
    "neo4j.vm.file.descriptors.maximum",
    # GC metrics
    "neo4j.vm.gc.count.g1_old_generation.count",
    "neo4j.vm.gc.count.g1_young_generation.count",
    "neo4j.vm.gc.time.g1_old_generation.count",
    "neo4j.vm.gc.time.g1_young_generation.count",
    # JVM Heap metrics
    "neo4j.vm.heap.committed",
    "neo4j.vm.heap.used",
    "neo4j.vm.heap.max",
    # JVM memory buffers metrics
    "neo4j.vm.memory.buffer.direct_count",
    "neo4j.vm.memory.buffer.direct_used",
    "neo4j.vm.memory.buffer.direct_capacity",
    # JVM memory pools metrics
    "neo4j.vm.memory.pool.compressed_class_space",
    "neo4j.vm.memory.pool.g1_eden_space",
    "neo4j.vm.memory.pool.g1_old_gen",
    "neo4j.vm.memory.pool.g1_survivor_space",
    "neo4j.vm.memory.pool.metaspace",
    # JVM pause time metrics
    "neo4j.vm.pause_time.count",
    # JVM threads metrics
    "neo4j.vm.threads",
  ]

  metrics_widgets_map = {
    3: local.v3x_metrics,
    4: local.v4x_metrics,
    5: local.v5x_metrics,
  }

  # select the right widget based on neo4j version
  metrics_widgets = lookup(local.metrics_widgets_map, var.neo4j_major_version_number, local.v4x_metrics)
  metrics_last_commited_transaction_id = "neo4j.last_committed_tx_id"

  # Inefficient queries dashboard dynamic widgets
  timeseries_definitions = [
    # --- Cluster health context ---
    {
      title        = "Query Volume by User"
      search_query = "environment:${var.environment} service:neo4j sourcecategory:query"
      aggregation  = "count"
      group_by     = "@executingUser"
      limit        = 10
      sort         = "desc"
      pos_x        = 0
      pos_y        = 0
      width        = 12
      height       = 4
    },
    {
      title        = "Avg Query Elapsed Time (ms)"
      search_query = "environment:${var.environment} service:neo4j sourcecategory:query"
      aggregation  = "avg"
      metric       = "@elapsedTimeMs"
      pos_x        = 0
      pos_y        = 4
      width        = 6
      height       = 3
    },
    {
      title        = "Total Page Faults by User (cache pressure)"
      search_query = "environment:${var.environment} service:neo4j sourcecategory:query"
      aggregation  = "sum"
      metric       = "@pageFaults"
      group_by     = "@executingUser"
      limit        = 10
      sort         = "desc"
      pos_x        = 6
      pos_y        = 4
      width        = 6
      height       = 3
    },
    # --- Slow queries by user ---
    {
      title        = "Slow queries (500ms - 5s) by user"
      search_query = "environment:${var.environment} service:neo4j sourcecategory:query @elapsedTimeMs:[500 TO 5000]"
      aggregation  = "count"
      group_by     = "@executingUser"
      limit        = 10
      sort         = "desc"
      pos_x        = 0
      pos_y        = 7
      width        = 6
      height       = 4
    },
    {
      title        = "Very slow queries (>5s) by user"
      search_query = "environment:${var.environment} service:neo4j sourcecategory:query @elapsedTimeMs:>5000"
      aggregation  = "count"
      group_by     = "@executingUser"
      limit        = 10
      sort         = "desc"
      pos_x        = 6
      pos_y        = 7
      width        = 6
      height       = 4
    },
    # --- Page fault load by user ---
    {
      title        = "High page fault queries (>=50) by user"
      search_query = "environment:${var.environment} service:neo4j sourcecategory:query @pageFaults:>=50"
      aggregation  = "count"
      group_by     = "@executingUser"
      limit        = 10
      sort         = "desc"
      pos_x        = 0
      pos_y        = 11
      width        = 6
      height       = 4
    },
    # --- Lock/pool contention by user ---
    {
      title        = "Queries with wait >1s (lock/pool contention) by user"
      search_query = "environment:${var.environment} service:neo4j sourcecategory:query @waiting:>1000"
      aggregation  = "count"
      group_by     = "@executingUser"
      limit        = 10
      sort         = "desc"
      pos_x        = 6
      pos_y        = 11
      width        = 6
      height       = 4
    },
  ]

  query_table_definitions = [
    {
      title          = "Slow Query Rate by User — normalized by total query volume"
      group_by_facet = "@executingUser"
      queries = [
        {
          name         = "query1"
          search_query = "environment:${var.environment} service:neo4j sourcecategory:query @elapsedTimeMs:[500 TO 5000]"
          aggregation  = "count"
          limit        = 20
        },
        {
          name         = "query2"
          search_query = "environment:${var.environment} service:neo4j sourcecategory:query @elapsedTimeMs:>5000"
          aggregation  = "count"
          limit        = 20
        },
        {
          name         = "query3"
          search_query = "environment:${var.environment} service:neo4j sourcecategory:query"
          aggregation  = "count"
          limit        = 1000
        },
      ]
      formulas = [
        {
          expression = "query1"
          alias      = "# Slow (500ms-5s)"
        },
        {
          expression = "query2"
          alias      = "# Very Slow (>5s)"
        },
        {
          expression = "query3"
          alias      = "Total Queries"
        },
        {
          expression   = "(query1 + query2) / query3 * 100"
          alias        = "Slow Query Rate %"
          limit_clause = true
          limit_count  = 20
          limit_order  = "desc"
        },
      ]
      pos_x  = 0
      pos_y  = 15
      width  = 12
      height = 5
    },
    {
      title          = "DB Load by User — Total Time & Page Faults"
      group_by_facet = "@executingUser"
      queries = [
        {
          name         = "query1"
          search_query = "environment:${var.environment} service:neo4j sourcecategory:query"
          aggregation  = "count"
          limit        = 1000
        },
        {
          name         = "query2"
          search_query = "environment:${var.environment} service:neo4j sourcecategory:query"
          aggregation  = "sum"
          metric       = "@elapsedTimeMs"
          limit        = 20
        },
        {
          name         = "query3"
          search_query = "environment:${var.environment} service:neo4j sourcecategory:query"
          aggregation  = "avg"
          metric       = "@elapsedTimeMs"
          limit        = 20
        },
        {
          name         = "query4"
          search_query = "environment:${var.environment} service:neo4j sourcecategory:query"
          aggregation  = "sum"
          metric       = "@pageFaults"
          limit        = 20
        },
        {
          name         = "query5"
          search_query = "environment:${var.environment} service:neo4j sourcecategory:query"
          aggregation  = "max"
          metric       = "@elapsedTimeMs"
          limit        = 20
        },
      ]
      formulas = [
        {
          expression = "query1"
          alias      = "# Queries"
        },
        {
          expression   = "query2"
          alias        = "Total DB Time (ms)"
          limit_clause = true
          limit_count  = 20
          limit_order  = "desc"
        },
        {
          expression = "query3"
          alias      = "Avg Query Time (ms)"
        },
        {
          expression = "query4"
          alias      = "Total Page Faults"
        },
        {
          expression = "query5"
          alias      = "Max Query Time (ms)"
        },
      ]
      pos_x  = 0
      pos_y  = 20
      width  = 12
      height = 6
    },
  ]

  log_stream_definitions = [
    {
      title       = "Slowest queries (>500ms)"
      query       = "environment:${var.environment} service:neo4j sourcecategory:query @elapsedTimeMs:>500"
      columns     = ["timestamp", "@executingUser", "@elapsedTimeMs", "@pageHits", "@pageFaults", "@waiting", "@query"]
      sort_column = "@elapsedTimeMs"
      pos_x       = 0
      pos_y       = 26
      width       = 12
      height      = 5
    },
    {
      title       = "Highest page fault queries (>=50 faults)"
      query       = "environment:${var.environment} service:neo4j sourcecategory:query @pageFaults:>=50"
      columns     = ["timestamp", "@executingUser", "@elapsedTimeMs", "@pageHits", "@pageFaults", "@query"]
      sort_column = "@pageFaults"
      pos_x       = 0
      pos_y       = 31
      width       = 12
      height      = 5
    },
  ]

  # Node and relationship count data is available for Prod V5
  show_node_rel_count_widget = (var.environment == "prod" && var.neo4j_major_version_number >= 4) ? [1] : []
  # Only team tags are supported for dashboards
  dashboard_tags = [for team in var.teams : "team:${team}"]

  tags = flatten([
    "env:${var.environment}",
    "environment:${var.environment}",
    "service:${var.service_name}",
    "service_name:${var.service_name}",
    [for team in var.teams : "team:${team}"],
    [for dependent_application in var.dependent_applications : "dependent_application:${dependent_application}"]
  ])
}
