terraform {
  required_providers {
    proxmox = {
      source  = "Telmate/proxmox"
      version = "3.0.2-rc04"
    }
    random = {
      source  = "hashicorp/random"
      version = "3.7.2"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "2.38.0"
    }
    helm = {
      source  = "hashicorp/helm"
      version = "3.0.2"
    }
  }
}

provider "proxmox" {
  pm_api_url      = var.proxmox_url
  pm_user         = var.proxmox_user
  pm_password     = var.proxmox_password
  pm_tls_insecure = var.proxmox_tls_insecure
}

# ----------------------
# Generate k3s token
# ----------------------
resource "random_password" "k3s_token" {
  length  = 32
  special = false
}

# ----------------------
# Controller VM
# ----------------------
resource "proxmox_vm_qemu" "controller" {
  name        = "k3s-controller"
  target_node = var.target_nodes["controller"]
  clone_id       = var.template_id
  full_clone  = true
  cpu {
    cores = 2
    sockets     = 1
  }
  memory      = 1024
  scsihw      = "virtio-scsi-pci"
  disks {
    scsi {
      scsi0 {
        disk {
          storage = var.storage
          size    = "20G" 
        }
      }
    }
    ide {
      ide1 {
        cloudinit {
          storage = var.storage
        }
      }
    }
  }
  network {
    id     = 0
    model  = "virtio"
    bridge = var.bridge
  }
  ipconfig0 = "ip=${var.controller_ip}/${var.netmask},gw=${var.gateway}"
  ciuser = var.admin_user
  cipassword = var.admin_password
  sshkeys = var.ssh_public_key

  cicustom = <<EOT
#cloud-config
package_update: true
packages:
  - curl
runcmd:
  - |
    curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --cluster-init --token=${random_password.k3s_token.result} --write-kubeconfig-mode=644" sh -
EOT
}

# ----------------------
# Worker 1 VM
# ----------------------
resource "proxmox_vm_qemu" "worker1" {
  name        = "k3s-worker1"
  target_node = var.target_nodes["worker1"]
  clone_id       = var.template_id
  full_clone  = true
  cpu {
    cores = 2
    sockets     = 1
  }
  memory      = 1024
  scsihw      = "virtio-scsi-pci"
  disks {
    scsi {
      scsi0 {
        disk {
          storage = var.storage
          size    = "20G" 
        }
      }
    }
    ide {
      ide1 {
        cloudinit {
          storage = var.storage
        }
      }
    }
  }
  network {
    id     = 0
    model  = "virtio"
    bridge = var.bridge
  }
  ipconfig0 = "ip=${var.worker1_ip}/${var.netmask},gw=${var.gateway}"
  ciuser = var.admin_user
  cipassword = var.admin_password
  sshkeys = var.ssh_public_key

  cicustom = <<EOT
#cloud-config
package_update: true
packages:
  - curl
runcmd:
  - |
    curl -sfL https://${var.controller_ip}:6443 | K3S_URL=https://${var.controller_ip}:6443 K3S_TOKEN=${random_password.k3s_token.result} sh -
EOT
}

# ----------------------
# Worker 2 VM
# ----------------------
resource "proxmox_vm_qemu" "worker2" {
  name        = "k3s-worker2"
  target_node = var.target_nodes["worker2"]
  clone_id       = var.template_id
  full_clone  = true
  cpu {
    cores = 2
    sockets     = 1
  }
  memory      = 1024
  scsihw      = "virtio-scsi-pci"
  disks {
    scsi {
      scsi0 {
        disk {
          storage = var.storage
          size    = "20G" 
        }
      }
    }
    ide {
      ide1 {
        cloudinit {
          storage = var.storage
        }
      }
    }
  }
  network {
    id     = 0
    model  = "virtio"
    bridge = var.bridge
  }
  ipconfig0 = "ip=${var.worker2_ip}/${var.netmask},gw=${var.gateway}"
  ciuser = var.admin_user
  cipassword = var.admin_password
  sshkeys = var.ssh_public_key

  cicustom = <<EOT
#cloud-config
package_update: true
packages:
  - curl
runcmd:
  - |
    curl -sfL https://${var.controller_ip}:6443 | K3S_URL=https://${var.controller_ip}:6443 K3S_TOKEN=${random_password.k3s_token.result} sh -
EOT
}

# ----------------------
# Kubernetes & Helm Providers (after cluster is ready)
# ----------------------
provider "kubernetes" {
  config_path = "~/.kube/config"
}

provider "helm" {
  kubernetes = {
    config_path = "~/.kube/config"
  }
}

# ----------------------
# Namespaces
# ----------------------
resource "kubernetes_namespace" "infra" {
  metadata {
    name = "infra"
  }
}
resource "kubernetes_namespace" "devops" {
  metadata {
    name = "devops"
  }
}

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

# ----------------------
# Ingress
# ----------------------
resource "helm_release" "nginx_ingress" {
  name       = "nginx-ingress"
  namespace  = kubernetes_namespace.infra.metadata[0].name
  repository = "https://kubernetes.github.io/ingress-nginx"
  chart      = "ingress-nginx"
  version    = "4.10.0"
}

# ----------------------
# cert-manager
# ----------------------
resource "helm_release" "cert_manager" {
  name       = "cert-manager"
  namespace  = kubernetes_namespace.infra.metadata[0].name
  repository = "https://charts.jetstack.io"
  chart      = "cert-manager"
  version    = "v1.15.1"
  values     = [<<EOT
installCRDs: true
EOT
  ]
  depends_on = [helm_release.nginx_ingress]
}

# ----------------------
# CoreDNS authoritative for lab.local
# ----------------------
resource "helm_release" "coredns" {
  name       = "coredns-ext"
  namespace  = kubernetes_namespace.infra.metadata[0].name
  repository = "https://coredns.github.io/helm"
  chart      = "coredns"
  version    = "1.30.0"
  values     = [file("${path.module}/values/coredns-values.yaml")]
}

# ----------------------
# NTP Deployment
# ----------------------
resource "kubernetes_deployment" "ntp" {
  metadata {
    name      = "ntp-server"
    namespace = kubernetes_namespace.infra.metadata[0].name
  }

  spec {
    replicas = 1

    selector {
      match_labels = {
        app = "ntp"
      }
    }

    template {
      metadata {
        labels = {
          app = "ntp"
        }
      }

      spec {
        container {
          name  = "ntp"
          image = "cturra/ntp:latest"

          port {
            container_port = 123
            protocol       = "UDP"
          }
        }
      }
    }
  }
}

resource "kubernetes_service" "ntp" {
  metadata {
    name      = "ntp-service"
    namespace = kubernetes_namespace.infra.metadata[0].name
  }

  spec {
    selector = {
      app = "ntp"
    }

    port {
      port        = 123
      target_port = 123
      protocol    = "UDP"
    }

    type = "ClusterIP"
  }
}


# ----------------------
# GitLab Helm Release
# ----------------------
resource "helm_release" "gitlab" {
  name       = "gitlab"
  namespace  = kubernetes_namespace.devops.metadata[0].name
  repository = "https://charts.gitlab.io/"
  chart      = "gitlab"
  version    = "7.7.0"
  values     = [file("${path.module}/values/gitlab-values.yaml")]
  depends_on = [helm_release.nginx_ingress, helm_release.cert_manager]
}

# ----------------------
# Logging Stack
# ----------------------
resource "helm_release" "loki" {
  name       = "loki"
  namespace  = kubernetes_namespace.monitoring.metadata[0].name
  repository = "https://grafana.github.io/helm-charts"
  chart      = "loki"
  version    = "5.41.4"
  values     = [file("${path.module}/values/loki-values.yaml")]
}

resource "helm_release" "promtail" {
  name       = "promtail"
  namespace  = kubernetes_namespace.monitoring.metadata[0].name
  repository = "https://grafana.github.io/helm-charts"
  chart      = "promtail"
  version    = "6.15.5"
  values     = [file("${path.module}/values/promtail-values.yaml")]
  depends_on = [helm_release.loki]
}

resource "helm_release" "grafana" {
  name       = "grafana"
  namespace  = kubernetes_namespace.monitoring.metadata[0].name
  repository = "https://grafana.github.io/helm-charts"
  chart      = "grafana"
  version    = "7.3.9"
  values     = [file("${path.module}/values/grafana-values.yaml")]
  depends_on = [helm_release.loki]
}
