provider "aws" {
  region = var.aws_region
}

# ── EKS auth data sources ─────────────────────────────────────────────────────
# These data sources read the EKS cluster endpoint and CA certificate so that
# the helm and kubernetes providers can authenticate to the cluster.
#
# Single-phase apply:
#   `depends_on` on the data sources defers their read until after module.eks
#   has been applied. The kubernetes/helm providers therefore receive their
#   configuration at apply time. All resources we create through these providers
#   (kubernetes_storage_class_v1, helm_release.*) avoid plan-time API calls,
#   so a fresh `terraform apply` works in one shot.

data "aws_eks_cluster" "this" {
  name       = module.eks.cluster_name
  depends_on = [module.eks]
}

data "aws_eks_cluster_auth" "this" {
  name       = module.eks.cluster_name
  depends_on = [module.eks]
}

# Helm provider — connects to EKS using a short-lived token from the AWS SDK.
provider "helm" {
  kubernetes {
    host                   = data.aws_eks_cluster.this.endpoint
    cluster_ca_certificate = base64decode(data.aws_eks_cluster.this.certificate_authority[0].data)
    token                  = data.aws_eks_cluster_auth.this.token
  }
}

# Kubernetes provider — used for Namespaces, ServiceAccounts, StorageClass.
provider "kubernetes" {
  host                   = data.aws_eks_cluster.this.endpoint
  cluster_ca_certificate = base64decode(data.aws_eks_cluster.this.certificate_authority[0].data)
  token                  = data.aws_eks_cluster_auth.this.token
}

# ── Common locals ─────────────────────────────────────────────────────────────

locals {
  name = "${var.project_name}-${var.environment}"
  tags = merge(
    {
      Project     = var.project_name
      Environment = var.environment
      ManagedBy   = "terraform"
    },
    var.tags
  )
  effective_tikv_replicas   = coalesce(var.scale_tikv_replicas, var.tidb_x.tikv_replicas)
  pd_config_has_replication = length(regexall("(?m)^\\s*\\[replication\\]\\s*$", var.tidb_x.pd_config)) > 0
  effective_pd_config = trimspace(
    join(
      "\n",
      compact([
        trimspace(var.tidb_x.pd_config),
        local.pd_config_has_replication ? "" : "[replication]",
        local.pd_config_has_replication ? "" : "  max-replicas = ${local.effective_tikv_replicas}",
      ])
    )
  )
}

# ── VPC / Networking ──────────────────────────────────────────────────────────

module "network" {
  source = "../../modules/network"

  name                 = local.name
  vpc_cidr             = var.vpc_cidr
  availability_zones   = var.availability_zones
  private_subnet_cidrs = var.private_subnet_cidrs
  public_subnet_cidrs  = var.public_subnet_cidrs
  tags                 = local.tags
}

# ── EKS cluster ───────────────────────────────────────────────────────────────

module "eks" {
  source = "../../modules/eks"

  cluster_name       = local.name
  cluster_version    = var.eks_cluster_version
  vpc_id             = module.network.vpc_id
  private_subnet_ids = module.network.private_subnet_ids

  eks_managed_node_groups = {
    main = {
      desired_size   = var.node_desired_size
      min_size       = var.node_min_size
      max_size       = var.node_max_size
      instance_types = var.node_instance_types
      capacity_type  = "ON_DEMAND"
      subnet_ids     = [module.network.private_subnet_ids[0]]

      labels = {
        role = "general"
      }
    }
  }
  tags = local.tags
}

# ── VPC endpoints ─────────────────────────────────────────────────────────────
# Interface + S3 gateway endpoints keep EKS/AWS API traffic off the NAT gateway.

module "vpc_endpoints" {
  source = "../../modules/vpc_endpoints"

  name                    = local.name
  vpc_id                  = module.network.vpc_id
  aws_region              = var.aws_region
  interface_subnet_ids    = [module.network.private_subnet_ids[0]]
  private_route_table_ids = module.network.private_route_table_ids
  allowed_security_group_ids = [
    module.eks.node_security_group_id,
    module.eks.cluster_primary_security_group_id,
  ]
  interface_services = [
    "ecr.api",
    "ecr.dkr",
    "sts",
    "ec2",
  ]
  tags = local.tags
}

# ── EKS access ────────────────────────────────────────────────────────────────

module "access" {
  source = "../../modules/access"

  cluster_admin_principal_arn = var.cluster_admin_principal_arn
  cluster_name                = module.eks.cluster_name
  readonly_principal_arns     = var.readonly_principal_arns
  tags                        = local.tags
}

# ── K8s add-ons ───────────────────────────────────────────────────────────────
# Deploys the EBS CSI driver (AWS add-on), the gp3 StorageClass, metrics-server,
# and optionally ingress-nginx — all via Terraform (Helm + kubernetes provider).

module "addons" {
  source = "../../modules/addons"

  cluster_name          = module.eks.cluster_name
  enable_ingress_nginx  = var.enable_ingress_nginx
  enable_metrics_server = var.enable_metrics_server
  ebs_csi_role_arn      = module.eks.ebs_csi_role_arn
  tags                  = local.tags
}

# ── TiDB-X cluster ────────────────────────────────────────────────────────────
# Installs the tidb-operator via Helm, creates the IRSA S3 role/ServiceAccount,
# and deploys all TiDB cluster CRD instances (Cluster, PDGroup, TiKVGroup, etc.)
# using a local Helm chart.  Everything is idempotent: re-running terraform apply
# updates only the resources that differ from the desired state.

module "tidb_x" {
  source = "../../modules/tidb_x"

  # ── AWS context ──
  aws_region        = var.aws_region
  eks_cluster_name  = module.eks.cluster_name
  oidc_provider_arn = module.eks.oidc_provider_arn
  tags              = local.tags

  # ── Operator ──
  operator_namespace     = var.tidb_x.operator_namespace
  operator_chart_version = var.tidb_x.operator_chart_version
  operator_image         = var.tidb_x.operator_image
  operator_image_tag     = var.tidb_x.operator_image_tag

  # ── Cluster identity ──
  cluster_name      = var.tidb_x.cluster_name
  cluster_namespace = var.tidb_x.cluster_namespace
  cluster_version   = var.tidb_x.cluster_version

  # ── S3 ──
  s3_bucket_name     = var.tidb_x.s3_bucket_name
  s3_create_bucket   = var.tidb_x.s3_create_bucket
  s3_service_account = var.tidb_x.s3_service_account

  # ── PD ──
  pd_image      = var.tidb_x.pd_image
  pd_version    = var.tidb_x.pd_version
  pd_replicas   = coalesce(var.scale_pd_replicas, var.tidb_x.pd_replicas)
  pd_storage    = var.tidb_x.pd_storage
  pd_config     = local.effective_pd_config
  pd_extra_spec = var.tidb_x.pd_extra_spec

  # ── TiKV ──
  tikv_image      = var.tidb_x.tikv_image
  tikv_version    = var.tidb_x.tikv_version
  tikv_replicas   = coalesce(var.scale_tikv_replicas, var.tidb_x.tikv_replicas)
  tikv_storage    = var.tidb_x.tikv_storage
  tikv_config     = var.tidb_x.tikv_config
  tikv_extra_spec = var.tidb_x.tikv_extra_spec

  # ── TiDB ──
  tidb_image    = var.tidb_x.tidb_image
  tidb_version  = var.tidb_x.tidb_version
  tidb_replicas = coalesce(var.scale_tidb_replicas, var.tidb_x.tidb_replicas)
  tidb_config   = var.tidb_x.tidb_config

  # ── PD TSO microservice ──
  pd_tso_enabled  = var.tidb_x.pd_tso_enabled
  pd_tso_image    = var.tidb_x.pd_tso_image
  pd_tso_version  = var.tidb_x.pd_tso_version
  pd_tso_replicas = coalesce(var.scale_pd_tso_replicas, var.tidb_x.pd_tso_replicas)

  # ── PD Scheduling microservice ──
  pd_scheduling_enabled  = var.tidb_x.pd_scheduling_enabled
  pd_scheduling_image    = var.tidb_x.pd_scheduling_image
  pd_scheduling_version  = var.tidb_x.pd_scheduling_version
  pd_scheduling_replicas = coalesce(var.scale_pd_scheduling_replicas, var.tidb_x.pd_scheduling_replicas)

  # ── TiProxy ──
  tiproxy_enabled  = var.tidb_x.tiproxy_enabled
  tiproxy_image    = var.tidb_x.tiproxy_image
  tiproxy_version  = var.tidb_x.tiproxy_version
  tiproxy_replicas = coalesce(var.scale_tiproxy_replicas, var.tidb_x.tiproxy_replicas)

  # ── TiFlash write ──
  tiflash_write_enabled    = var.tidb_x.tiflash_write_enabled
  tiflash_write_image      = var.tidb_x.tiflash_write_image
  tiflash_write_version    = var.tidb_x.tiflash_write_version
  tiflash_write_replicas   = coalesce(var.scale_tiflash_write_replicas, var.tidb_x.tiflash_write_replicas)
  tiflash_write_storage    = var.tidb_x.tiflash_write_storage
  tiflash_write_config     = var.tidb_x.tiflash_write_config
  tiflash_write_extra_spec = var.tidb_x.tiflash_write_extra_spec

  # ── TiFlash compute ──
  tiflash_compute_enabled    = var.tidb_x.tiflash_compute_enabled
  tiflash_compute_image      = var.tidb_x.tiflash_compute_image
  tiflash_compute_version    = var.tidb_x.tiflash_compute_version
  tiflash_compute_replicas   = coalesce(var.scale_tiflash_compute_replicas, var.tidb_x.tiflash_compute_replicas)
  tiflash_compute_storage    = var.tidb_x.tiflash_compute_storage
  tiflash_compute_config     = var.tidb_x.tiflash_compute_config
  tiflash_compute_extra_spec = var.tidb_x.tiflash_compute_extra_spec
}
