# Variables ===================================================================

variable "name_prefix" {
  description = "Prefix prepended to resource names created by this module"
  type        = string

  validation {
    condition     = length(trimspace(var.name_prefix)) > 0
    error_message = "name_prefix must not be empty."
  }
}

variable "tags" {
  description = "Tags applied to all resources in this module."
  type        = map(string)
  default     = {}
}

variable "vaults" {
  description = <<-EOT
    Map of centralized backup vaults to create in the hub account.
    Each vault carries its own list of trusted spoke role ARNs (principals
    allowed to backup:CopyIntoBackupVault) so that different vaults can
    enforce different trust boundaries — e.g. a compliance-tier vault
    restricted to a subset of spoke accounts.
  EOT
  type = map(object({
    name_suffix = string
    kms_key_arn = optional(string, null)

    # Principals (spoke account backup service roles) allowed to copy
    # recovery points into this vault. Required — a vault with an empty
    # list accepts no cross-account copies.
    trusted_spoke_role_arns = list(string)

    # Vault lock (WORM compliance mode)
    lock_enabled             = optional(bool, false)
    lock_changeable_for_days = optional(number, 3)
    lock_min_retention_days  = optional(number, null)
    lock_max_retention_days  = optional(number, null)

    # Notifications — fully opt-in, no default events fire unless listed.
    # Set sns_topic_arn to reuse an existing topic; leave null and set
    # create_sns_topic = true to have the module provision one.
    notifications = optional(object({
      sns_topic_arn       = optional(string, null)
      create_sns_topic    = optional(bool, false)
      kms_key_arn         = optional(string, null)
      backup_vault_events = list(string)
    }), null)
  }))
  default = {}

  validation {
    condition = alltrue([
      for k, v in var.vaults : can(regex("^[a-zA-Z0-9_-]+$", v.name_suffix))
    ])
    error_message = <<-EOT
      Vault name_suffix values must contain only alphanumerics, hyphens,
      and underscores (no dots, spaces, or other characters).
    EOT
  }

  validation {
    condition = alltrue([
      for k, v in var.vaults :
      v.lock_enabled ? (v.lock_min_retention_days != null) : true
    ])
    error_message = <<-EOT
      lock_min_retention_days is required when lock_enabled is true.
      Set a retention floor, or leave lock_enabled = false for this vault.
    EOT
  }

  validation {
    condition = alltrue([
      for k, v in var.vaults :
      v.lock_enabled && v.lock_min_retention_days != null ?
      v.lock_min_retention_days >= 1 :
      true
    ])
    error_message = "lock_min_retention_days must be at least 1 day."
  }

  validation {
    condition = alltrue([
      for k, v in var.vaults :
      v.lock_enabled && v.lock_max_retention_days != null ?
      v.lock_max_retention_days >= 1 :
      true
    ])
    error_message = "lock_max_retention_days must be at least 1 day."
  }

  validation {
    condition = alltrue([
      for k, v in var.vaults :
      (v.lock_enabled && v.lock_min_retention_days != null && v.lock_max_retention_days != null) ?
      v.lock_max_retention_days >= v.lock_min_retention_days :
      true
    ])
    error_message = <<-EOT
      lock_max_retention_days must be greater than or equal to
      lock_min_retention_days when both are set.
    EOT
  }

  validation {
    condition = alltrue([
      for k, v in var.vaults :
      v.lock_enabled ? v.lock_changeable_for_days >= 3 : true
    ])
    error_message = <<-EOT
      lock_changeable_for_days must be at least 3 — AWS Backup enforces a
      minimum 3-day cooling-off period before compliance mode locks in
      permanently.
    EOT
  }

  validation {
    condition = alltrue([
      for k, v in var.vaults : length(v.trusted_spoke_role_arns) > 0
    ])
    error_message = <<-EOT
      Every hub vault must define at least one trusted_spoke_role_arns entry.
      A vault with an empty list can never receive cross-account copies.
    EOT
  }

  validation {
    condition = alltrue([
      for k, v in var.vaults :
      v.notifications == null ? true : (
        v.notifications.sns_topic_arn != null || v.notifications.create_sns_topic
      )
    ])
    error_message = <<-EOT
      When notifications is set, you must either:
        - provide an existing sns_topic_arn, or
        - set create_sns_topic = true to have the module provision one.
    EOT
  }

  validation {
    condition = alltrue([
      for k, v in var.vaults :
      v.notifications == null ? true : length(v.notifications.backup_vault_events) > 0
    ])
    error_message = <<-EOT
      notifications.backup_vault_events must list at least one event
      when notifications is configured for a vault.
    EOT
  }

  validation {
    condition = alltrue(flatten([
      for k, v in var.vaults : [
        for event in(v.notifications == null ? [] : v.notifications.backup_vault_events) :
        contains(local.valid_vault_events_for_notifications, event)
      ]
    ]))
    error_message = <<-EOT
      notifications.backup_vault_events contains an event not recognized
      by AWS Backup.

      Valid Events:
        ${join("\n  ", [for chunk in chunklist(local.valid_vault_events_for_notifications, 3) : join(", ", chunk)])}
    EOT
  }
}
