terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
    awscc = {
      source  = "hashicorp/awscc"
      version = "~> 1.64"
    }
  }

  backend "s3" {
    bucket       = "autonomous-deployment-terraform-state"
    region       = "us-west-2"
    use_lockfile = true
  }
}

provider "aws" {
  profile = "default"
  region  = "us-west-2"
  alias   = "tf_state"
}

provider "aws" {
  profile = local.clinic_outputs.account.value
  region  = "us-west-2"
}

provider "awscc" {
  profile = var.account
  region  = "us-west-2"
}

provider "aws" {
  profile = local.base_outputs.account.value
  region  = "us-west-2"
  alias   = "pca_owner"
}

provider "aws" {
  profile = var.account
  region  = "us-west-2"
  alias   = "pca_accepter"
}

variable "env" {
  type = string
}

variable "account" {
  type = string
}

variable "plan" {
  type = string
}

locals {
  states = {
    "base" : "aws/base/${var.env}.json",
    "seed" : "aws/account/seed/${var.env}.json",
    "clinic" : var.env == "dev" ? "aws/clinic/staging.json" : "aws/clinic/${var.env}.json",
  }
}

data "aws_s3_object" "states" {
  for_each = local.states
  bucket   = "autonomous-deployment-terraform-state"
  key      = each.value

  provider = aws.tf_state
}

locals {
  base_outputs   = jsondecode(data.aws_s3_object.states["base"].body).outputs
  seed_outputs   = jsondecode(data.aws_s3_object.states["seed"].body).outputs
  clinic_outputs = jsondecode(data.aws_s3_object.states["clinic"].body).outputs
}

resource "aws_vpc_endpoint_service_allowed_principal" "clinic_endpoint_service" {
  vpc_endpoint_service_id = local.clinic_outputs.endpoint_service_id.value
  principal_arn           = "arn:aws:iam::${var.account}:root"
}

# This resource freezes the CloudFormation stack name so that existing accounts
# that were provisioned with a non-default stack name are not broken when the
# stack_name is later managed by Terraform.
#
# Default value: "tidbcloud-premium-setup-dataplane"
#
# For accounts that already have a CloudFormation stack with a different name,
# follow these steps before applying normally:
#   1. Temporarily set `input` below to the existing stack name for that account.
#   2. Run `terraform apply` — this creates the terraform_data resource with the
#      old name frozen as its output.
#   3. Revert `input` back to the default value "tidbcloud-premium-setup-dataplane".
#   4. Run `terraform apply` again — the change to `input` is ignored due to
#      `ignore_changes = all`, so the stack name remains unchanged.
#
# For new accounts, no action is needed — the default name is used automatically.
resource "terraform_data" "backward_compatible" {
  input = "tidbcloud-premium-setup-dataplane"

  lifecycle {
    # Prevent Terraform from ever updating the output after initial creation.
    # This ensures the frozen stack name is never changed by subsequent applies.
    ignore_changes = all
  }
}

resource "awscc_cloudformation_stack" "tidbcloud_premium_setup_dataplane" {
  count = var.plan == "premium" ? 1 : 0

  stack_name                    = terraform_data.backward_compatible.output
  enable_termination_protection = false
  capabilities                  = ["CAPABILITY_NAMED_IAM"]

  parameters = {
    ControlPlaneAccountId = local.seed_outputs.base_account.value
    ClinicAccountId       = local.clinic_outputs.account.value
  }

  template_body = file("${path.module}/cloudformation/tidbcloud-premium-setup-dataplane.yaml")

  tags = [{
    key   = "auto_deploy_owner_tag"
    value = "premium"
  }]
}

module "pca" {
  count            = var.plan == "premium" ? 1 : 0
  source           = "../../aws_modules/pca-share"
  owner_account    = local.base_outputs.account.value
  accepter_account = var.account
  resource_arn     = local.base_outputs.pca_arn.value

  providers = {
    aws.owner    = aws.pca_owner
    aws.accepter = aws.pca_accepter
  }
}

output "env" {
  value = var.env
}

output "base_account" {
  value = local.seed_outputs.base_account.value
}

output "seed_account" {
  value = local.seed_outputs.seed_account.value
}

output "shoot_account" {
  value = var.account
}

output "plan" {
  value = var.plan
}