terraform {
  required_version = ">= 1.0"

  backend "s3" {
    bucket         = "jiraport-tf-state-166681434446"
    key            = "eks/terraform.tfstate"
    region         = "us-west-1"
    dynamodb_table = "jiraport-tf-lock"
    encrypt        = true
  }

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    helm = {
      source  = "hashicorp/helm"
      version = ">= 2.9"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = ">= 2.20"
    }
  }
}

provider "aws" {
  region = "us-west-1"
}

provider "kubernetes" {
  host                   = module.eks.cluster_endpoint
  cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = "aws"
    # This requires the awscli to be installed locally where Terraform is executed
    args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
  }
}

provider "helm" {
  kubernetes = {
    host                   = module.eks.cluster_endpoint
    cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)

    exec = {
      api_version = "client.authentication.k8s.io/v1beta1"
      command     = "aws"
      args        = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
    }
  }
}

variable "environment" {
  description = "The deployment environment (dev, prod)"
  type        = string
  default     = "dev"
}

variable "certificate_arn" {
  description = "ARN of the ACM certificate for the ALB"
  type        = string
  default     = "arn:aws:acm:us-west-1:166681434446:certificate/b0ef49c5-6e9f-43e6-8939-1aeb2655c6cd"
}

variable "domain_name" {
  description = "Domain name for the ALB"
  type        = string
  default     = "jiraport-alert-eks-dev.pingcap.net"
}

variable "jiraport_secrets" {
  description = "Map of secrets to inject into the Kubernetes Secret"
  type        = map(string)
  sensitive   = true
  default     = {}
}

################################################################################
# Kubernetes Namespace & Secrets
################################################################################

resource "kubernetes_namespace" "jiraport" {
  metadata {
    name = "jiraport-${var.environment}"
  }

  depends_on = [module.eks]
}

resource "kubernetes_secret" "jiraport_secrets" {
  metadata {
    name      = "jiraport-secrets-${var.environment}"
    namespace = kubernetes_namespace.jiraport.metadata[0].name
  }

  data = var.jiraport_secrets
  type = "Opaque"
}

################################################################################
# AWS Load Balancer Controller
################################################################################

module "load_balancer_controller_irsa_role" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
  version = "~> 5.0"

  role_name                              = "load-balancer-controller-${var.environment}"
  attach_load_balancer_controller_policy = true

  oidc_providers = {
    ex = {
      provider_arn               = module.eks.oidc_provider_arn
      namespace_service_accounts = ["kube-system:aws-load-balancer-controller"]
    }
  }
}

resource "helm_release" "aws_load_balancer_controller" {
  name       = "aws-load-balancer-controller"
  repository = "https://aws.github.io/eks-charts"
  chart      = "aws-load-balancer-controller"
  namespace  = "kube-system"
  version    = "1.6.2"

  set = [
    {
      name  = "clusterName"
      value = module.eks.cluster_name
    },
    {
      name  = "serviceAccount.create"
      value = "true"
    },
    {
      name  = "serviceAccount.name"
      value = "aws-load-balancer-controller"
    },
    {
      name  = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
      value = module.load_balancer_controller_irsa_role.iam_role_arn
    }
  ]
}

################################################################################
# Fluent Bit for CloudWatch Logs
################################################################################

module "fluent_bit_irsa_role" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
  version = "~> 5.0"

  role_name = "fluent-bit-${var.environment}"

  role_policy_arns = {
    policy = "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
  }

  oidc_providers = {
    ex = {
      provider_arn               = module.eks.oidc_provider_arn
      namespace_service_accounts = ["amazon-cloudwatch:fluent-bit"]
    }
  }
}

resource "helm_release" "aws_for_fluent_bit" {
  name             = "aws-for-fluent-bit"
  repository       = "https://aws.github.io/eks-charts"
  chart            = "aws-for-fluent-bit"
  namespace        = "amazon-cloudwatch"
  create_namespace = true
  version          = "0.1.33"

  set = [
    {
      name  = "cloudWatchLogs.region"
      value = local.region
    },
    {
      name  = "cloudWatchLogs.logGroupName"
      value = "/aws/eks/${local.name}/application"
    },
    {
      name  = "cloudWatchLogs.autoCreateGroup"
      value = "true"
    },
    {
      name  = "serviceAccount.create"
      value = "true"
    },
    {
      name  = "serviceAccount.name"
      value = "fluent-bit"
    },
    {
      name  = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
      value = module.fluent_bit_irsa_role.iam_role_arn
    }
  ]

  depends_on = [module.eks]
}

################################################################################
# JiraPort Application
################################################################################

# resource "helm_release" "jiraport" {
#   name      = "jiraport-${var.environment}"
#   chart     = "${path.module}/../../charts/jiraport"
#   namespace = kubernetes_namespace.jiraport.metadata[0].name
#   wait      = false

#   values = [
#     var.environment == "dev" ? file("${path.module}/../../charts/jiraport/values-dev.yaml") : file("${path.module}/../../charts/jiraport/values-prod-tidbcloud.yaml")
#   ]

#   # Ensure ALB controller and secrets are ready before deploying application
#   depends_on = [
#     helm_release.aws_load_balancer_controller,
#     kubernetes_secret.jiraport_secrets
#   ]

#   set = [
#     {
#       name  = "ingress.enabled"
#       value = "true"
#     },
#     {
#       name  = "ingress.className"
#       value = "alb"
#     },
#     {
#       name  = "ingress.annotations.alb\\.ingress\\.kubernetes\\.io/scheme"
#       value = "internet-facing"
#     },
#     {
#       name  = "ingress.annotations.alb\\.ingress\\.kubernetes\\.io/target-type"
#       value = "ip"
#     },
#     {
#       name  = "ingress.annotations.alb\\.ingress\\.kubernetes\\.io/certificate-arn"
#       value = var.certificate_arn
#     },
#     {
#       name  = "ingress.hosts[0].host"
#       value = var.domain_name
#     },
#     {
#       name  = "ingress.hosts[0].paths[0].path"
#       value = "/"
#     },
#     {
#       name  = "ingress.hosts[0].paths[0].pathType"
#       value = "Prefix"
#     }
#   ]

#   # Add more sets here if needed for api.image.repository, etc.
# }

# Update the EKS module to a newer version that supports AWS Provider v5 fully
# or keep 19.x if we pin the provider carefully.
# Let's try updating to v20.0.0+ which is definitely compatible, 
# BUT v20 has breaking changes. 
# Safer fix for now: stick to v19 but ensure we use a version known to work with provider v5,
# or pin provider to < 5.0 if we want to keep module as is.
# The errors indicate the module IS trying to use removed fields, so the module is likely too OLD for provider v5.
# EKS module v19.16.0+ fixed some v5 issues. v19.21.0 is the latest v19.

data "aws_availability_zones" "available" {}

locals {
  name   = "jiraport-${var.environment}"
  region = "us-west-1"

  vpc_cidr = "10.0.0.0/16"
  azs      = slice(data.aws_availability_zones.available.names, 0, 2)

  tags = {
    Environment = var.environment
    Example     = local.name
    GithubRepo  = "terraform-aws-eks"
    GithubOrg   = "terraform-aws-modules"
  }
}

################################################################################
# VPC
################################################################################

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"

  name = local.name
  cidr = local.vpc_cidr

  azs             = local.azs
  private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)]
  public_subnets  = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 4)]

  enable_nat_gateway = true
  single_nat_gateway = true

  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }

  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = 1
  }

  tags = local.tags
}

################################################################################
# EKS Cluster
################################################################################

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 19.21"

  cluster_name    = local.name
  cluster_version = "1.34"

  vpc_id                         = module.vpc.vpc_id
  subnet_ids                     = module.vpc.private_subnets
  cluster_endpoint_public_access = true

  eks_managed_node_group_defaults = {
    ami_type = "AL2023_x86_64_STANDARD"
  }

  eks_managed_node_groups = {
    one = {
      name            = "ng-${var.environment}-2"
      use_name_prefix = false

      instance_types = ["t3.small"]

      min_size     = var.environment == "dev" ? 1 : 2
      max_size     = 3
      desired_size = var.environment == "dev" ? 1 : 2
    }
  }

  # aws-auth configmap
  manage_aws_auth_configmap = true

  # Add your IAM user here so you can access the cluster after creation
  aws_auth_users = [
    {
      userarn  = var.environment == "dev" ? aws_iam_user.github_actions[0].arn : data.aws_iam_user.existing_github_actions[0].arn
      username = var.environment == "dev" ? aws_iam_user.github_actions[0].name : data.aws_iam_user.existing_github_actions[0].user_name
      groups   = ["system:masters"]
    }
  ]

  tags = local.tags
}

################################################################################
# OIDC Provider (Necessary for Load Balancer Controller)
################################################################################


output "cluster_endpoint" {
  description = "Endpoint for EKS control plane"
  value       = module.eks.cluster_endpoint
}

output "cluster_security_group_id" {
  description = "Security group ids attached to the cluster control plane"
  value       = module.eks.cluster_security_group_id
}

output "region" {
  description = "AWS region"
  value       = local.region
}

output "cluster_name" {
  description = "Kubernetes Cluster Name"
  value       = module.eks.cluster_name
}
