terraform {
  required_version = ">= 1.7"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.27"
    }
  }
  backend "s3" {
    bucket         = "veylant-terraform-state"
    key            = "production/eks/terraform.tfstate"
    region         = "eu-west-3"
    encrypt        = true
    dynamodb_table = "veylant-terraform-locks"
  }
}

provider "aws" {
  region = var.aws_region
  default_tags {
    tags = {
      Project     = "veylant-ia"
      Environment = "production"
      ManagedBy   = "terraform"
    }
  }
}

# ──────────────────────────────────────────────
# VPC — 3 public + 3 private subnets across AZs
# ──────────────────────────────────────────────
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.5"

  name = "veylant-production"
  cidr = var.vpc_cidr

  azs             = ["${var.aws_region}a", "${var.aws_region}b", "${var.aws_region}c"]
  private_subnets = var.private_subnet_cidrs
  public_subnets  = var.public_subnet_cidrs

  enable_nat_gateway     = true
  single_nat_gateway     = false  # 1 NAT GW per AZ for HA
  enable_dns_hostnames   = true
  enable_dns_support     = true

  # Required tags for EKS auto-discovery of subnets.
  private_subnet_tags = {
    "kubernetes.io/role/internal-elb"             = "1"
    "kubernetes.io/cluster/${var.cluster_name}"   = "owned"
  }
  public_subnet_tags = {
    "kubernetes.io/role/elb"                      = "1"
    "kubernetes.io/cluster/${var.cluster_name}"   = "owned"
  }
}

# ──────────────────────────────────────────────
# EKS Cluster — Kubernetes 1.31, eu-west-3
# ──────────────────────────────────────────────
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.0"

  cluster_name    = var.cluster_name
  cluster_version = "1.31"

  vpc_id                         = module.vpc.vpc_id
  subnet_ids                     = module.vpc.private_subnet_ids
  cluster_endpoint_public_access = true   # Access via kubectl from CI/CD

  # Enable IRSA — required for pod-level IAM roles (backup, Vault).
  enable_irsa = true

  cluster_addons = {
    aws-ebs-csi-driver = {
      most_recent = true
      service_account_role_arn = module.irsa_ebs_csi.iam_role_arn
    }
    coredns = {
      most_recent = true
    }
    kube-proxy = {
      most_recent = true
    }
    vpc-cni = {
      most_recent    = true
      before_compute = true
    }
  }

  eks_managed_node_groups = {
    # One node group per AZ for topology-aware scheduling.
    veylant-az-a = {
      name           = "veylant-az-a"
      subnet_ids     = [module.vpc.private_subnets[0]]
      instance_types = [var.node_instance_type]
      min_size       = 1
      max_size       = 5
      desired_size   = 2
      ami_type       = "AL2_x86_64"
      disk_size      = 50

      labels = {
        "topology.kubernetes.io/zone" = "${var.aws_region}a"
        workload                      = "veylant"
      }
    }

    veylant-az-b = {
      name           = "veylant-az-b"
      subnet_ids     = [module.vpc.private_subnets[1]]
      instance_types = [var.node_instance_type]
      min_size       = 1
      max_size       = 5
      desired_size   = 2
      ami_type       = "AL2_x86_64"
      disk_size      = 50

      labels = {
        "topology.kubernetes.io/zone" = "${var.aws_region}b"
        workload                      = "veylant"
      }
    }

    veylant-az-c = {
      name           = "veylant-az-c"
      subnet_ids     = [module.vpc.private_subnets[2]]
      instance_types = [var.node_instance_type]
      min_size       = 1
      max_size       = 5
      desired_size   = 2
      ami_type       = "AL2_x86_64"
      disk_size      = 50

      labels = {
        "topology.kubernetes.io/zone" = "${var.aws_region}c"
        workload                      = "veylant"
      }
    }
  }

  tags = {
    Environment = "production"
    Cluster     = var.cluster_name
  }
}

# ──────────────────────────────────────────────
# IRSA — IAM Roles for Service Accounts
# ──────────────────────────────────────────────

# EBS CSI Driver IRSA
module "irsa_ebs_csi" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
  version = "~> 5.39"

  role_name             = "veylant-ebs-csi-driver"
  attach_ebs_csi_policy = true

  oidc_providers = {
    main = {
      provider_arn               = module.eks.oidc_provider_arn
      namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]
    }
  }
}

# Backup role IRSA (S3 write for pg_dump)
module "irsa_backup" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
  version = "~> 5.39"

  role_name = "veylant-backup-role"

  role_policy_arns = {
    backup = aws_iam_policy.backup_s3.arn
  }

  oidc_providers = {
    main = {
      provider_arn               = module.eks.oidc_provider_arn
      namespace_service_accounts = ["veylant:veylant-backup"]
    }
  }
}

resource "aws_iam_policy" "backup_s3" {
  name        = "veylant-backup-s3"
  description = "Allow Veylant backup job to write to S3 backup bucket"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "s3:PutObject",
          "s3:GetObject",
          "s3:ListBucket",
          "s3:DeleteObject"
        ]
        Resource = [
          "arn:aws:s3:::veylant-backups-production",
          "arn:aws:s3:::veylant-backups-production/*"
        ]
      }
    ]
  })
}

# ──────────────────────────────────────────────
# S3 Backup Bucket with 7-day lifecycle
# ──────────────────────────────────────────────
resource "aws_s3_bucket" "backups" {
  bucket = "veylant-backups-production"
}

resource "aws_s3_bucket_versioning" "backups" {
  bucket = aws_s3_bucket.backups.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "backups" {
  bucket = aws_s3_bucket.backups.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

resource "aws_s3_bucket_lifecycle_configuration" "backups" {
  bucket = aws_s3_bucket.backups.id

  rule {
    id     = "expire-old-backups"
    status = "Enabled"

    filter {
      prefix = "postgres/"
    }

    # Delete backups older than 7 days.
    expiration {
      days = 7
    }

    # Clean up incomplete multipart uploads.
    abort_incomplete_multipart_upload {
      days_after_initiation = 1
    }
  }
}

resource "aws_s3_bucket_public_access_block" "backups" {
  bucket                  = aws_s3_bucket.backups.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}
