resource "kubernetes_namespace" "stunnel" {
  metadata {
    name = "stunnel"
    annotations = {
      name = "stunnel"
    }
    labels = {
      name = "stunnel"
    }
  }
}

resource "kubernetes_service_account" "stunnel_service_account" {

  metadata {
    name      = "stunnel-app-sa"
    namespace = kubernetes_namespace.stunnel.metadata[0].name
  }

  automount_service_account_token = false
}


resource "kubernetes_config_map" "wireguard_config" {
  count = local.wireguard_config != "null" ? 1 : 0
  metadata {
    name      = "wireguard-config"
    namespace = kubernetes_namespace.stunnel.metadata[0].name
  }

  data = {
    "wireguard.conf" = local.wireguard_config
  }
}

resource "kubernetes_config_map" "stunnel_config" {
  metadata {
    name      = "stunnel-config"
    namespace = kubernetes_namespace.stunnel.metadata[0].name
  }

  data = {
    "stunnel.conf" = local.stunnel_config
  }
}

resource "kubernetes_deployment" "stunnel" {

  metadata {
    name      = "stunnel"
    namespace = kubernetes_namespace.stunnel.metadata[0].name

    annotations = {
      "security.alpha.kubernetes.io/unsafe-sysctls" = "net.ipv4.conf.all.src_valid_mark=1"
    }
  }

  spec {
    replicas = 1

    selector {
      match_labels = {
        app = "stunnel"
      }
    }

    strategy {
      type = "Recreate"
    }

    template {
      metadata {
        labels = {
          app = "stunnel"
        }
        annotations = {
          "checksum/stunnel"   = local.stunnel_config_checksum
          "checksum/wireguard" = local.wireguard_config_checksum
        }
      }
      spec {

        dynamic "container" {
          for_each = nonsensitive(local.wireguard_config) != "null" ? [1] : []
          content {

            name  = "wireguard"
            image = "linuxserver/wireguard:${local.wireguard_version}"

            resources {
              requests = {
                memory = "64Mi"
              }
            }

            liveness_probe {
              exec {
                command = [
                  "/bin/sh",
                  "-c",
                  "wg show | grep -q transfer"
                ]
              }
              initial_delay_seconds = 90
              period_seconds        = 90
            }

            security_context {
              privileged = true
              capabilities {
                add = ["NET_ADMIN"]
              }
              read_only_root_filesystem = true
            }

            env {
              name  = "PUID"
              value = "1000"
            }

            env {
              name  = "PGID"
              value = "1000"
            }

            env {
              name  = "TZ"
              value = "Europe/Berlin"
            }

            volume_mount {
              name       = "wireguard-config"
              mount_path = "/config/wg_confs"
              read_only  = true
            }

            volume_mount {
              name       = "lib-modules"
              mount_path = "/lib/modules"
              read_only  = true
            }

            volume_mount {
              name       = "wireguard-run"
              mount_path = "/run"
            }
          }
        }

        container {
          name  = "stunnel"
          image = "chainguard/stunnel:${local.stunnel_version}"
          args  = ["/etc/conf/stunnel.conf"]
          volume_mount {
            name       = "stunnel-config"
            mount_path = "/etc/conf"
            read_only  = true
          }
          volume_mount {
            name       = "stunnel-certs"
            mount_path = "/etc/ssl/certs/private"
            read_only  = true
          }
          dynamic "port" {
            for_each = var.remote_targets
            content {
              container_port = port.value.listen_port
              name           = substr(replace(port.key, ".", "-"), 0, 15)
              protocol       = coalesce(upper(port.value.protocol), "TCP")
            }
          }
        }

        dynamic "volume" {
          for_each = nonsensitive(local.wireguard_config) != "null" ? [1] : []
          content {
            name = "wireguard-config"
            config_map {
              name = nonsensitive(kubernetes_config_map.wireguard_config[0].metadata[0].name)
            }
          }
        }

        dynamic "volume" {
          for_each = nonsensitive(local.wireguard_config) != "null" ? [1] : []
          content {
            name = "lib-modules"
            host_path {
              path = "/lib/modules"
            }
          }
        }

        dynamic "volume" {
          for_each = nonsensitive(local.wireguard_config) != "null" ? [1] : []
          content {
            name = "wireguard-run"
            empty_dir {
              medium = "Memory"
            }
          }
        }

        volume {
          name = "stunnel-config"
          config_map {
            name = kubernetes_config_map.stunnel_config.metadata[0].name
          }
        }

        volume {
          name = "stunnel-certs"
          secret {
            secret_name = "remote-targets-cert"
          }
        }
      }
    }
  }

  lifecycle {
    ignore_changes = [spec[0].template[0].metadata[0].annotations["kubectl.kubernetes.io/restartedAt"]]
  }
}

resource "kubernetes_manifest" "remote_targets_cert" {

  manifest = {
    apiVersion = "cert-manager.io/v1"
    kind       = "Certificate"
    metadata = {
      name      = "remote-targets-cert"
      namespace = kubernetes_namespace.stunnel.metadata[0].name
    }
    spec = {
      secretName = "remote-targets-cert"
      issuerRef = {
        name = var.issuer_name
        kind = "ClusterIssuer"
      }
      commonName = "stunnel.remote_targets.internal"
      dnsNames = flatten([
        for k, v in var.remote_targets : "${k}.stunnel.svc.cluster.local"
      ])
    }
  }
}

resource "kubernetes_manifest" "local_targets_cert" {

  manifest = {
    apiVersion = "cert-manager.io/v1"
    kind       = "Certificate"
    metadata = {
      name      = "local-targets-cert"
      namespace = kubernetes_namespace.stunnel.metadata[0].name
    }
    spec = {
      secretName = "local-targets-cert"
      issuerRef = {
        name = var.issuer_name
        kind = "ClusterIssuer"
      }
      commonName = "stunnel.local_targets.internal"
      dnsNames = flatten([
        for _, v in var.local_targets : v.target_host
      ])
    }
  }
}

resource "kubernetes_service" "services" {
  for_each = var.remote_targets
  metadata {
    name      = format("%s", replace(each.key, ".", "-"))
    namespace = kubernetes_namespace.stunnel.metadata[0].name
  }
  spec {
    port {
      name        = substr(format("%s", replace(each.key, ".", "-")), 0, 15)
      port        = each.value.listen_port
      target_port = substr(format("%s", replace(each.key, ".", "-")), 0, 15)
    }
    selector = {
      app = "stunnel"
    }
    type = "ClusterIP"
  }
}
