locals {
  nextcloud_env_vars = {
    # Database configuration
    MYSQL_DATABASE = "nextcloud"
    MYSQL_HOST     = module.nextcloud_database.host

    # Email configuration
    SMTP_HOST         = local.scaleway_smtp_host
    SMTP_SECURE       = "ssl"
    SMTP_PORT         = 465
    MAIL_FROM_ADDRESS = "cloud"
    MAIL_DOMAIN       = "alexpires.me"
    SMTP_AUTHTYPE     = "PLAIN"

    # Redis configuration
    REDIS_HOST = "redis"

    # Object as primary storage
    OBJECTSTORE_S3_HOST       = "s3.${scaleway_object_bucket.nextcloud.region}.scw.cloud"
    OBJECTSTORE_S3_BUCKET     = scaleway_object_bucket.nextcloud.name
    OBJECTSTORE_S3_PORT       = 443
    OBJECTSTORE_S3_SSL        = true
    OBJECTSTORE_S3_REGION     = scaleway_object_bucket.nextcloud.region
    OBJECTSTORE_S3_AUTOCREATE = false

    # General
    NEXTCLOUD_TRUSTED_DOMAINS = local.nextcloud_fqdn
    TRUSTED_PROXIES           = join(" ", ["10.1.0.0/16"])
    OVERWRITEHOST             = local.nextcloud_fqdn
    OVERWRITEPROTOCOL         = "https"
    OVERWRITECLIURL           = "https://${local.nextcloud_fqdn}"

    # PHP
    PHP_MEMORY_LIMIT = "512M"
  }

  nextcloud_secrets = {

    OBJECTSTORE_S3_KEY = {
      key  = "access_key"
      name = kubernetes_secret.nextcloud_object_store_credentials.metadata[0].name
    }

    OBJECTSTORE_S3_SECRET = {
      key  = "secret_key"
      name = kubernetes_secret.nextcloud_object_store_credentials.metadata[0].name
    }

    SMTP_NAME = {
      key  = "username"
      name = kubernetes_secret.nextcloud_mail_credentials.metadata[0].name
    }

    SMTP_PASSWORD = {
      key  = "password"
      name = kubernetes_secret.nextcloud_mail_credentials.metadata[0].name
    }

    MYSQL_USER = {
      key  = "username"
      name = module.nextcloud_database.app_crendentials_name
    }

    MYSQL_PASSWORD = {
      key  = "password"
      name = module.nextcloud_database.app_crendentials_name
    }

    NEXTCLOUD_ADMIN_USER = {
      key  = "username"
      name = kubernetes_secret.nextcloud_admin_credentials.metadata[0].name
    }

    NEXTCLOUD_ADMIN_PASSWORD = {
      key  = "password"
      name = kubernetes_secret.nextcloud_admin_credentials.metadata[0].name
    }
  }

  nextcloud_path        = "${local.persistent_folder}/nextcloud"
  nextcloud_db_path     = "${local.database_folder}/mysql.nextcloud"
  nextcloud_backup_path = "${local.persistent_folder}/backup.gitea"
}

#
# Namespace
#
resource "kubernetes_namespace" "nextcloud" {
  metadata {
    annotations = {
      name = "nextcloud"
    }

    labels = {
      name = "nextcloud"
    }

    name = "nextcloud"
  }
}

#
# Nextcloud required credentials
#
resource "kubernetes_secret" "nextcloud_mail_credentials" {
  metadata {
    name      = "nextcloud-mail-credentials"
    namespace = kubernetes_namespace.nextcloud.metadata[0].name
  }
  data = {
    username = var.scaleway_project_id
    password = scaleway_iam_api_key.mail_app_api.secret_key
  }
  type = "Opaque"
}

resource "kubernetes_secret" "nextcloud_object_store_credentials" {
  metadata {
    name      = "nextcloud-object-store-credentials"
    namespace = kubernetes_namespace.nextcloud.metadata[0].name
  }
  data = {
    access_key = scaleway_iam_api_key.nextcloud_app_api.access_key
    secret_key = scaleway_iam_api_key.nextcloud_app_api.secret_key
  }
  type = "Opaque"
}

resource "kubernetes_secret" "nextcloud_admin_credentials" {
  metadata {
    name      = "nextcloud-admin-credentials"
    namespace = kubernetes_namespace.nextcloud.metadata[0].name
  }
  data = {
    username = "admin"
    password = var.nextcloud_admin_password
  }
  type = "Opaque"
}

resource "kubernetes_config_map" "nextcloud_apache_config" {
  metadata {
    name      = "nextcloud-apache-config"
    namespace = kubernetes_namespace.nextcloud.metadata[0].name
  }
  data = {
    "99-nextcloudworkers.conf" = file("${path.module}/resources/apache2/99-nextcloudworkers.conf")
    "99-compression.conf"      = file("${path.module}/resources/apache2/99-compression.conf")
  }

}

#
# Setup MariaDB database
#
module "nextcloud_database" {
  source = "../modules/db/mariadb"

  namespace = kubernetes_namespace.nextcloud.metadata[0].name
  app_name  = "nextcloud"

  app_password  = var.nextcloud_mysql_password
  root_password = var.mysql_root_password

  retention_days = local.local_backup_retention_days
  cron_schedule  = local.nextcloud_sql_backup_cron_schedule

  database_folder = local.nextcloud_db_path
  backup_folder   = local.nextcloud_backup_path
}

# 
# Nextcloud service, ingress, deployment and file backup job
#
#
resource "kubernetes_service_account" "nextcloud_service_account" {

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

  automount_service_account_token = false
}

resource "kubernetes_service" "nextcloud_redis" {
  metadata {
    name      = "redis"
    namespace = kubernetes_namespace.nextcloud.metadata[0].name
  }
  spec {
    port {
      port = 6379
      name = "redis"
    }
    selector = {
      app = "redis"
    }
    cluster_ip = "None"
  }
}

resource "kubernetes_service" "nextcloud_apache" {
  metadata {
    name      = "http"
    namespace = kubernetes_namespace.nextcloud.metadata[0].name
  }
  spec {
    port {
      port        = 80
      target_port = "http"
    }
    selector = {
      app = "nextcloud"
    }
    cluster_ip = "None"
  }
}

resource "kubernetes_ingress_v1" "nextcloud_ingress" {
  depends_on = [
    kubernetes_deployment.nextcloud_apache
  ]
  metadata {
    name      = "nextcloud-ingress"
    namespace = kubernetes_namespace.nextcloud.metadata[0].name

    annotations = {
      "kubernetes.io/ingress.class"                         = "public"
      "cert-manager.io/cluster-issuer"                      = "letsencrypt-prod"
      "kubernetes.io/tls-acme"                              = "true"
      "nginx.ingress.kubernetes.io/ssl-redirect"            = "true"
      "nginx.ingress.kubernetes.io/proxy-body-size"         = "4G"
      "nginx.ingress.kubernetes.io/proxy-request-buffering" = "on"
      "nginx.ingress.kubernetes.io/proxy-buffer-size"       = "32k"
      "nginx.ingress.kubernetes.io/proxy-buffers-number"    = "16"
      "nginx.ingress.kubernetes.io/server-snippet"          = file("${path.module}/resources/nextcloud-server-snippet.conf")
    }
  }
  spec {
    tls {
      hosts       = [local.nextcloud_fqdn]
      secret_name = "nextcloud-tls"
    }
    rule {
      host = local.nextcloud_fqdn
      http {
        path {
          backend {
            service {
              name = "http"
              port {
                number = 80
              }
            }
          }
        }
      }
    }
  }
}

resource "kubernetes_deployment" "nextcloud_redis" {
  metadata {
    name      = "redis"
    namespace = kubernetes_namespace.nextcloud.metadata[0].name
  }
  spec {
    selector {
      match_labels = {
        app = "redis"
      }
    }
    strategy {
      type = "RollingUpdate"
    }
    template {
      metadata {
        labels = {
          app = "redis"
        }
      }
      spec {
        container {
          name  = "redis"
          image = "redis:latest"

          security_context {
            allow_privilege_escalation = false
          }

          readiness_probe {
            tcp_socket {
              port = "redis"
            }
            initial_delay_seconds = 10
            period_seconds        = 15
            success_threshold     = 1
            failure_threshold     = 3
          }

          liveness_probe {
            tcp_socket {
              port = "redis"
            }
            initial_delay_seconds = 10
            period_seconds        = 15
            success_threshold     = 1
            failure_threshold     = 3
          }

          port {
            container_port = 6379
            name           = "redis"
            protocol       = "TCP"
          }
        }
      }
    }
  }
}

resource "kubernetes_deployment" "nextcloud_apache" {

  depends_on = [
    module.nextcloud_database,
    kubernetes_deployment.nextcloud_redis
  ]

  metadata {
    name      = "nextcloud-app"
    namespace = kubernetes_namespace.nextcloud.metadata[0].name
  }
  spec {
    selector {
      match_labels = {
        app = "nextcloud"
      }
    }
    strategy {
      type = "Recreate"
    }
    template {
      metadata {
        labels = {
          app = "nextcloud"
        }
      }
      spec {
        service_account_name = kubernetes_service_account.nextcloud_service_account.metadata[0].name

        container {
          name              = "nextcloud"
          image             = "nextcloud:${local.nextcloud_version}"
          image_pull_policy = "Always"

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

          readiness_probe {
            http_get {
              port = "http"
              path = "/status.php"
            }
            initial_delay_seconds = 30
            period_seconds        = 10
            success_threshold     = 1
            failure_threshold     = 3
          }

          liveness_probe {
            tcp_socket {
              port = "http"
            }
            initial_delay_seconds = 5
            period_seconds        = 10
            success_threshold     = 1
            failure_threshold     = 3
          }

          dynamic "env" {
            for_each = local.nextcloud_env_vars
            content {
              name  = env.key
              value = env.value
            }
          }
          security_context {
            allow_privilege_escalation = false
          }

          dynamic "env" {
            for_each = local.nextcloud_secrets
            content {
              name = env.key
              value_from {
                secret_key_ref {
                  key  = env.value.key
                  name = env.value.name
                }
              }
            }
          }

          port {
            container_port = 80
            name           = "http"
          }

          volume_mount {
            mount_path = "/var/www/html"
            name       = "persistent-storage"
          }

          volume_mount {
            mount_path = "/etc/apache2/conf-enabled/99-nextcloudworkers.conf"
            name       = "apache-config"
            sub_path   = "99-nextcloudworkers.conf"
            read_only  = true
          }
          volume_mount {
            mount_path = "/etc/apache2/conf-enabled/99-compression.conf"
            name       = "apache-config"
            sub_path   = "99-compression.conf"
            read_only  = true
          }
        }
        volume {
          name = "persistent-storage"
          host_path {
            path = local.nextcloud_path
          }
        }
        volume {
          name = "apache-config"
          config_map {
            name = kubernetes_config_map.nextcloud_apache_config.metadata[0].name
          }
        }
      }
    }
  }
  lifecycle {
    replace_triggered_by = [
      kubernetes_deployment.nextcloud_redis
    ]
  }
}

resource "kubernetes_cron_job_v1" "nextcloud_cron_apache" {
  depends_on = [
    kubernetes_deployment.nextcloud_apache
  ]
  metadata {
    namespace = kubernetes_namespace.nextcloud.metadata[0].name
    name      = "cronjob-trigger"
  }
  spec {
    schedule                      = "*/15 * * * *"
    concurrency_policy            = "Forbid"
    failed_jobs_history_limit     = 2
    successful_jobs_history_limit = 2
    job_template {
      metadata {
        labels = {
          app = "cronjob-trigger"
        }
      }
      spec {
        backoff_limit           = 1
        parallelism             = 1
        completions             = 1
        active_deadline_seconds = 300
        template {
          metadata {
            labels = {
              app = "cronjob-trigger"
            }
          }
          spec {
            container {
              name  = "nextcloud"
              image = "nextcloud:${local.nextcloud_version}"

              command = ["curl"]
              args    = ["--fail", "-L", "http://http/cron.php"]
              security_context {
                allow_privilege_escalation = false
              }
            }
            restart_policy                   = "Never"
            termination_grace_period_seconds = 30
          }
        }
      }
    }
  }
  lifecycle {
    replace_triggered_by = [
      kubernetes_deployment.nextcloud_apache
    ]
  }
}
