terraform {
  # 1.11 is the floor for `use_lockfile` below. Set high rather than exact on purpose: too high
  # fails with a readable "required_version" message, too low fails with "Unsupported argument"
  # inside a backend block, which reads like a typo in this file.
  required_version = ">= 1.11"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.70"
    }
    # Used by the account guard below. Undeclared until now, which meant nothing constrained it and
    # the lock file was the only record that it existed at all.
    null = {
      source  = "hashicorp/null"
      version = "~> 3.2"
    }
  }

  # State lives in an S3 bucket created by hand during the admin window (see the runbook). It cannot
  # be created by Terraform, because Terraform needs somewhere to put its state before it can create
  # anything.
  #
  # Locking is the S3 native lock object, NOT a DynamoDB table. The design doc specified DynamoDB,
  # which was the only option when Terraform's S3 backend had no locking of its own. It now does,
  # and the table earned its removal three times over: one less resource in the account, one less
  # step in the admin window, and, the one that actually matters, the lock is now an object in the
  # state bucket. That means the bucket policy that grants the deploy role access to state grants it
  # access to the lock too. A DynamoDB table would have needed a separate grant in the deploy role's
  # identity policy, which was missing, and the symptom would have been the post-admin Terraform
  # test failing at the very moment admin was going away.
  #
  # Values are deliberately absent here and passed with `-backend-config` at init, so this file
  # carries no account number. The repository is private today; the account is still not something
  # to write down in a file that may be copied, forked, or opened in a screen share.
  backend "s3" {
    key          = "mcp/terraform.tfstate"
    region       = "us-west-2"
    encrypt      = true
    use_lockfile = true
  }
}

provider "aws" {
  region = var.region

  # Every resource carries these. `ManagedBy` is the one that matters operationally: it tells the
  # next person that changing this in the console will be reverted by the next apply, and where to
  # go instead.
  default_tags {
    tags = {
      Project   = "tidbcloud-mcp"
      ManagedBy = "terraform"
      Repo      = var.repo_slug
    }
  }
}

# A guard, not decoration.
#
# The operator's default AWS profile points at a DIFFERENT account (the chainscope project, in
# ap-southeast-1), and an apply with the wrong profile exported would create this entire stack
# there. That is not a hypothetical: it is the state this machine was in when the account was first
# checked. The account id is supplied as a variable and verified here, so a wrong profile fails at
# plan time with a readable message rather than succeeding somewhere expensive.
data "aws_caller_identity" "current" {}

resource "null_resource" "account_guard" {
  lifecycle {
    precondition {
      condition     = data.aws_caller_identity.current.account_id == var.account_id
      error_message = "Wrong AWS account: credentials resolve to ${data.aws_caller_identity.current.account_id}, expected ${var.account_id}. Check AWS_PROFILE."
    }
  }
}
