# Simulated fleet (T4 dev environment, docs/06) on the k3d cluster created
# by infra/ansible/sim-cluster.yml. Drones are StatefulSet replicas writing
# to a shared hostPath lake — the same /data contract as the on-board NVMe.

locals {
  labels = { "app.kubernetes.io/part-of" = "swarm-sim" }
}

resource "kubernetes_namespace" "swarm" {
  metadata {
    name   = var.namespace
    labels = local.labels
  }
}

# --- Fleet ------------------------------------------------------------------

resource "kubernetes_stateful_set" "drone" {
  metadata {
    name      = "drone"
    namespace = kubernetes_namespace.swarm.metadata[0].name
    labels    = local.labels
  }

  spec {
    service_name = "drone"
    replicas     = var.drone_count
    # A landed drone powers off; the next start is the next flight
    pod_management_policy = "Parallel"

    selector {
      match_labels = { app = "drone" }
    }

    template {
      metadata {
        labels = merge(local.labels, { app = "drone" })
      }

      spec {
        container {
          name              = "drone"
          image             = var.simulator_image
          image_pull_policy = "Never" # imported via k3d image import

          env {
            name = "DRONE_ID"
            value_from {
              field_ref {
                field_path = "metadata.name"
              }
            }
          }
          env {
            name  = "DURATION_S"
            value = tostring(var.flight_duration_s)
          }
          env {
            name  = "SPEEDUP"
            value = tostring(var.speedup)
          }
          env {
            name  = "DATA_DIR"
            value = "/data"
          }

          volume_mount {
            name       = "lake"
            mount_path = "/data"
          }

          resources {
            requests = { cpu = "50m", memory = "128Mi" }
            limits   = { cpu = "500m", memory = "512Mi" }
          }
        }

        volume {
          name = "lake"
          host_path {
            path = var.data_host_path
          }
        }
      }
    }
  }
}

# --- Exporter + Prometheus + Grafana (observability, docs/07) ----------------

resource "kubernetes_deployment" "exporter" {
  metadata {
    name      = "exporter"
    namespace = kubernetes_namespace.swarm.metadata[0].name
    labels    = local.labels
  }

  spec {
    replicas = 1
    selector {
      match_labels = { app = "exporter" }
    }
    template {
      metadata {
        labels = merge(local.labels, { app = "exporter" })
      }
      spec {
        container {
          name              = "exporter"
          image             = var.simulator_image
          image_pull_policy = "Never"
          command           = ["python", "monitoring/exporter.py"]
          env {
            name  = "DATA_DIR"
            value = "/data"
          }
          env {
            name  = "EXPORTER_PORT"
            value = "9105"
          }
          port {
            container_port = 9105
          }
          volume_mount {
            name       = "lake"
            mount_path = "/data"
            read_only  = true
          }
        }
        volume {
          name = "lake"
          host_path {
            path = var.data_host_path
          }
        }
      }
    }
  }
}

resource "kubernetes_service" "exporter" {
  metadata {
    name      = "exporter"
    namespace = kubernetes_namespace.swarm.metadata[0].name
  }
  spec {
    selector = { app = "exporter" }
    port {
      port        = 9105
      target_port = 9105
    }
  }
}

resource "kubernetes_deployment" "explorer" {
  metadata {
    name      = "explorer"
    namespace = kubernetes_namespace.swarm.metadata[0].name
    labels    = local.labels
  }

  spec {
    replicas = 1
    selector {
      match_labels = { app = "explorer" }
    }
    template {
      metadata {
        labels = merge(local.labels, { app = "explorer" })
      }
      spec {
        container {
          name              = "explorer"
          image             = var.simulator_image
          image_pull_policy = "Never"
          command           = ["python", "explorer/server.py"]
          env {
            name  = "DATA_DIR"
            value = "/data"
          }
          env {
            name  = "EXPLORER_PORT"
            value = "8088"
          }
          port {
            container_port = 8088
          }
          volume_mount {
            name       = "lake"
            mount_path = "/data"
            read_only  = true
          }
        }
        volume {
          name = "lake"
          host_path {
            path = var.data_host_path
          }
        }
      }
    }
  }
}

resource "kubernetes_service" "explorer" {
  metadata {
    name      = "explorer"
    namespace = kubernetes_namespace.swarm.metadata[0].name
  }
  spec {
    type     = "NodePort"
    selector = { app = "explorer" }
    port {
      port        = 8088
      target_port = 8088
      node_port   = var.node_ports.explorer
    }
  }
}

resource "kubernetes_config_map" "prometheus" {
  metadata {
    name      = "prometheus-config"
    namespace = kubernetes_namespace.swarm.metadata[0].name
  }
  data = {
    "prometheus.yml" = <<-EOT
      global:
        scrape_interval: 5s
      scrape_configs:
        - job_name: swarm
          static_configs:
            - targets: ["exporter:9105"]
    EOT
  }
}

resource "kubernetes_deployment" "prometheus" {
  metadata {
    name      = "prometheus"
    namespace = kubernetes_namespace.swarm.metadata[0].name
    labels    = local.labels
  }

  spec {
    replicas = 1
    selector {
      match_labels = { app = "prometheus" }
    }
    template {
      metadata {
        labels = merge(local.labels, { app = "prometheus" })
      }
      spec {
        container {
          name  = "prometheus"
          image = "prom/prometheus:v2.53.0"
          port {
            container_port = 9090
          }
          volume_mount {
            name       = "config"
            mount_path = "/etc/prometheus"
          }
        }
        volume {
          name = "config"
          config_map {
            name = kubernetes_config_map.prometheus.metadata[0].name
          }
        }
      }
    }
  }
}

resource "kubernetes_service" "prometheus" {
  metadata {
    name      = "prometheus"
    namespace = kubernetes_namespace.swarm.metadata[0].name
  }
  spec {
    type     = "NodePort"
    selector = { app = "prometheus" }
    port {
      port        = 9090
      target_port = 9090
      node_port   = var.node_ports.prometheus
    }
  }
}

resource "kubernetes_config_map" "grafana_provisioning" {
  metadata {
    name      = "grafana-provisioning"
    namespace = kubernetes_namespace.swarm.metadata[0].name
  }
  data = {
    "datasource.yml" = <<-EOT
      apiVersion: 1
      datasources:
        - name: Prometheus
          type: prometheus
          access: proxy
          url: http://prometheus:9090
          isDefault: true
    EOT
    "dashboards.yml" = <<-EOT
      apiVersion: 1
      providers:
        - name: swarm
          folder: ""
          type: file
          options:
            path: /var/lib/grafana/dashboards
    EOT
  }
}

resource "kubernetes_config_map" "grafana_dashboard" {
  metadata {
    name      = "grafana-dashboard"
    namespace = kubernetes_namespace.swarm.metadata[0].name
  }
  data = {
    "swarm.json" = file("${path.module}/../../../simulator/monitoring/grafana/dashboards/swarm.json")
  }
}

resource "kubernetes_deployment" "grafana" {
  metadata {
    name      = "grafana"
    namespace = kubernetes_namespace.swarm.metadata[0].name
    labels    = local.labels
  }

  spec {
    replicas = 1
    selector {
      match_labels = { app = "grafana" }
    }
    template {
      metadata {
        labels = merge(local.labels, { app = "grafana" })
      }
      spec {
        container {
          name  = "grafana"
          image = "grafana/grafana:11.1.0"
          port {
            container_port = 3000
          }

          env {
            name  = "GF_AUTH_ANONYMOUS_ENABLED"
            value = "true"
          }
          env {
            name  = "GF_AUTH_ANONYMOUS_ORG_ROLE"
            value = "Admin"
          }
          env {
            name  = "GF_AUTH_DISABLE_LOGIN_FORM"
            value = "true"
          }
          # Air-gap hygiene — same flags as the Compose profile
          env {
            name  = "GF_ANALYTICS_REPORTING_ENABLED"
            value = "false"
          }
          env {
            name  = "GF_ANALYTICS_CHECK_FOR_UPDATES"
            value = "false"
          }
          env {
            name  = "GF_ANALYTICS_CHECK_FOR_PLUGIN_UPDATES"
            value = "false"
          }

          volume_mount {
            name       = "provisioning-datasources"
            mount_path = "/etc/grafana/provisioning/datasources"
          }
          volume_mount {
            name       = "provisioning-dashboards"
            mount_path = "/etc/grafana/provisioning/dashboards"
          }
          volume_mount {
            name       = "dashboards"
            mount_path = "/var/lib/grafana/dashboards"
          }
        }

        volume {
          name = "provisioning-datasources"
          config_map {
            name = kubernetes_config_map.grafana_provisioning.metadata[0].name
            items {
              key  = "datasource.yml"
              path = "datasource.yml"
            }
          }
        }
        volume {
          name = "provisioning-dashboards"
          config_map {
            name = kubernetes_config_map.grafana_provisioning.metadata[0].name
            items {
              key  = "dashboards.yml"
              path = "dashboards.yml"
            }
          }
        }
        volume {
          name = "dashboards"
          config_map {
            name = kubernetes_config_map.grafana_dashboard.metadata[0].name
          }
        }
      }
    }
  }
}

resource "kubernetes_service" "grafana" {
  metadata {
    name      = "grafana"
    namespace = kubernetes_namespace.swarm.metadata[0].name
  }
  spec {
    type     = "NodePort"
    selector = { app = "grafana" }
    port {
      port        = 3000
      target_port = 3000
      node_port   = var.node_ports.grafana
    }
  }
}
