resource "kubernetes_namespace" "argocd" {
  metadata {
    name = "argocd"
  }
}

# Install cert-manager
resource "helm_release" "cert_manager" {
  name             = "cert-manager"
  repository       = "https://charts.jetstack.io"
  chart            = "cert-manager"
  version          = "v1.20.2"
  namespace        = "cert-manager"
  create_namespace = true

  set {
    name  = "installCRDs"
    value = "true"
  }

  set {
    name  = "prometheus.enabled"
    value = "false"
  }

  set {
    name  = "webhook.timeoutSeconds"
    value = "4"
  }
}

# Install nginx-ingress
resource "helm_release" "ingress_nginx" {
  name             = "ingress-nginx"
  repository       = "https://kubernetes.github.io/ingress-nginx"
  chart            = "ingress-nginx"
  version          = "4.14.2"
  namespace        = "ingress-nginx"
  create_namespace = true

  set {
    name  = "controller.service.type"
    value = "NodePort"
  }

  set {
    name  = "controller.service.nodePorts.http"
    value = "80"
  }

  set {
    name  = "controller.service.nodePorts.https"
    value = "443"
  }

  set {
    name  = "controller.ingressClassResource.default"
    value = "true"
  }

  set {
    name  = "controller.watchIngressWithoutClass"
    value = "true"
  }

  set {
    name  = "controller.hostPort.enabled"
    value = "true"
  }

  set {
    name  = "controller.service.externalTrafficPolicy"
    value = "Local"
  }
  set {
    name  = "controller.metrics.enabled"
    value = "true"
  }
  set {
    name  = "controller.metrics.serviceMonitor.enabled"
    value = "true"
  }
  set {
    name  = "controller.metrics.serviceMonitor.namespace"
    value = "prometheus"
  }
  set {
    name  = "controller.metrics.serviceMonitor.additionalLabels.release"
    value = "prometheus"
  }
  set {
    name  = "controller.metrics.serviceMonitor.additionalLabels.app"
    value = "ingress-nginx"
  }

}

# Check for cert-manager CRDs before proceeding
resource "null_resource" "wait_for_cert_manager_crds" {
  depends_on = [helm_release.cert_manager]

  provisioner "local-exec" {
    command = <<-EOT
      # Wait for cert-manager to be ready
      echo "Waiting for cert-manager CRDs to be available..."

      # Wait for the webhook to be ready first
      echo "Waiting for cert-manager webhook pod to be ready..."
      kubectl -n cert-manager wait --for=condition=ready pod -l app=webhook --timeout=120s

      # Try up to 10 times with increasing sleep between attempts
      for i in $(seq 1 10); do
        echo "Attempt $i to verify cert-manager CRDs..."

        # Check if the ClusterIssuer CRD exists
        if kubectl get crd clusterissuers.cert-manager.io > /dev/null 2>&1; then
          echo "ClusterIssuer CRD found!"
          exit 0
        fi

        # Increase wait time with each attempt
        sleep_time=$((i * 5))
        echo "CRDs not found yet, waiting $sleep_time seconds..."
        sleep $sleep_time
      done

      # If we get here, we've failed to find the CRDs
      echo "Failed to find cert-manager CRDs after multiple attempts"
      exit 1
    EOT
  }
}

# Note: ClusterIssuer is now managed outside of Terraform
# TODO: Automate the ClusterIssuer creation
# We've already created it manually with the setup_argocd.sh script

# Install ArgoCD
# This is the single source of truth for the ArgoCD deployment (previously
# also managed ad-hoc via `helm upgrade -f argocd-values.yaml`, which has been
# retired in favor of Terraform).
resource "helm_release" "argocd" {
  name       = "argocd"
  repository = "https://argoproj.github.io/argo-helm"
  chart      = "argo-cd"
  version    = "10.1.1"
  namespace  = kubernetes_namespace.argocd.metadata[0].name

  # Homelab: single-node K3s, no HA needed.
  values = [<<-EOT
    # Dex/notifications disabled - neither SSO federation nor notification
    # channels are configured, so avoid running two extra pods for nothing.
    dex:
      enabled: false

    notifications:
      enabled: false

    redis-ha:
      enabled: false

    redis:
      enabled: false

    # Use the Redis instance running on the K3s host itself instead of the
    # chart's bundled redis.
    # NOTE: this Redis has no auth (`requirepass` empty) and listens on
    # 0.0.0.0:6379 - reachable by anything on 192.168.1.0/24.
    externalRedis:
      host: 192.168.1.2
      port: 6379

    controller:
      metrics:
        enabled: true
        serviceMonitor:
          enabled: true

    configs:
      cm:
        timeout.reconciliation: 60s

    server:
      replicas: 1
      # Ingress terminates TLS, so the server can listen over plain HTTP.
      extraArgs:
        - --insecure
      ingress:
        enabled: true
        annotations:
          kubernetes.io/ingress.class: "nginx"
          kubernetes.io/tls-acme: "true"
          cert-manager.io/cluster-issuer: "letsencrypt-prod"
          nginx.ingress.kubernetes.io/proxy-body-size: 102400m
          nginx.ingress.kubernetes.io/auth-url: "https://pass.junv.cc/oauth2/auth"
          nginx.ingress.kubernetes.io/auth-signin: "https://pass.junv.cc/oauth2/start?rd=https://$host$escaped_request_uri"
        hostname: "argo.junv.cc"
        # `tls` is a boolean for this chart (not a list) - the actual secret
        # is always named `argocd-server-tls`.
        tls: true
      metrics:
        enabled: true
        serviceMonitor:
          enabled: true

    repoServer:
      replicas: 1
      metrics:
        enabled: true
        serviceMonitor:
          enabled: true

    applicationSet:
      metrics:
        enabled: true
        serviceMonitor:
          enabled: true

    global:
      logging:
        level: "warn"
  EOT
  ]

  depends_on = [
    helm_release.cert_manager,
    helm_release.ingress_nginx
  ]

  # Add timeout to ensure ArgoCD has enough time to install
  timeout = 900

  # Add retry logic in case of failure
  recreate_pods = true
}
