"""
zones.py — Kubernetes skill pack zones for NEXUS.
"""

from engine.zone import Zone
from engine.challenge import Challenge

ZONE_ORDER = [
    "pods_and_deployments",
    "services_and_networking",
    "configmaps_and_secrets",
    "namespaces_and_rbac",
    "helm_charts",
    "persistent_volumes",
    "resource_management",
    "network_policies",
    "cluster_troubleshooting",
    "statefulsets_and_daemonsets",
    "ingress_and_jobs",
]

ZONES = {
    "pods_and_deployments": Zone(
        id="pods_and_deployments",
        title="Pods and Deployments",
        description="Understand the fundamental units of Kubernetes: pods, deployments, and replica sets.",
        challenges=[
            Challenge(
                id="k8s_pod_def",
                type="quiz",
                prompt="In Kubernetes, what is the smallest deployable unit that can be created and managed?",
                options=["A Container", "A Pod", "A Deployment", "A Node"],
                answer="b",
                explanation="A Pod is the smallest deployable unit in Kubernetes. It can contain one or more containers that share network and storage.",
                url="https://kubernetes.io/docs/concepts/workloads/pods/",
                xp=10,
            ),
            Challenge(
                id="k8s_kubectl_get_pods",
                type="quiz",
                prompt="Which command lists all running pods in the current namespace?",
                options=["kubectl list pods", "kubectl show pods", "kubectl get pods", "kubectl describe pods"],
                answer="c",
                explanation="`kubectl get pods` lists all pods in the current namespace. Add `-A` or `--all-namespaces` to see pods across all namespaces.",
                xp=10,
            ),
            Challenge(
                id="k8s_deployment_purpose",
                type="quiz",
                prompt="What does a Kubernetes Deployment manage?",
                options=[
                    "A single Pod with no restart policy",
                    "A desired state for a set of identical Pods",
                    "Network routing rules between services",
                    "Persistent storage volumes",
                ],
                answer="b",
                explanation="A Deployment manages the desired state of a set of replica Pods. It handles rolling updates, rollbacks, and scaling.",
                xp=10,
            ),
            Challenge(
                id="k8s_replicas",
                type="quiz",
                prompt="A Deployment has `replicas: 3`. One Pod crashes. What does Kubernetes do?",
                options=[
                    "Nothing — the deployment is left with 2 pods",
                    "Alerts an operator to restart manually",
                    "Automatically creates a new Pod to maintain 3 replicas",
                    "Deletes the deployment",
                ],
                answer="c",
                explanation="Kubernetes continuously reconciles desired state with actual state. If a Pod dies, the Deployment controller creates a new one to maintain the specified replica count.",
                xp=10,
            ),
            Challenge(
                id="k8s_apply",
                type="fill_blank",
                prompt="To create or update resources from a YAML file, use: kubectl _____ -f deployment.yaml",
                answer="apply",
                explanation="`kubectl apply -f` creates resources if they don't exist or updates them if they do. It's the standard declarative way to manage Kubernetes resources.",
                xp=15,
                hints=["It's declarative — creates OR updates", "Opposite of 'destroy'"],
            ),
            Challenge(
                id="k8s_rollout",
                type="quiz",
                prompt="You updated a Deployment image. The rollout seems stuck. Which command shows the rollout status?",
                options=[
                    "kubectl status deployment my-app",
                    "kubectl rollout status deployment/my-app",
                    "kubectl get deployment my-app --watch",
                    "kubectl describe rollout my-app",
                ],
                answer="b",
                explanation="`kubectl rollout status deployment/my-app` streams the progress of a deployment rollout, showing how many replicas are updated and ready.",
                xp=15,
                hints=["The verb is 'rollout', not 'status'"],
            ),
        ],
    ),
    "services_and_networking": Zone(
        id="services_and_networking",
        title="Services and Networking",
        description="Route traffic to Pods using Services, DNS, and Ingress controllers.",
        challenges=[
            Challenge(
                id="k8s_service_purpose",
                type="quiz",
                prompt="Why do Kubernetes Pods need a Service to be reliably reachable?",
                options=[
                    "Pods are firewalled by default and can't receive traffic",
                    "Pod IP addresses are ephemeral — they change when Pods restart",
                    "Services provide TLS termination that Pods lack",
                    "Pods run in isolated VLANs",
                ],
                answer="b",
                explanation="Pods get new IP addresses every time they restart. A Service provides a stable virtual IP and DNS name that routes to healthy Pods via label selectors.",
                url="https://kubernetes.io/docs/concepts/services-networking/service/",
                xp=10,
            ),
            Challenge(
                id="k8s_clusterip",
                type="quiz",
                prompt="Which Service type is only reachable within the cluster (default)?",
                options=["NodePort", "LoadBalancer", "ExternalName", "ClusterIP"],
                answer="d",
                explanation="ClusterIP is the default Service type. It assigns a virtual IP only accessible within the cluster — useful for internal microservice communication.",
                xp=10,
            ),
            Challenge(
                id="k8s_nodeport",
                type="quiz",
                prompt="A NodePort Service exposes port 30080. How do you reach it from outside the cluster?",
                options=[
                    "curl http://cluster-name:30080",
                    "curl http://<any-node-ip>:30080",
                    "curl http://service-name:30080",
                    "You can't — NodePort is internal only",
                ],
                answer="b",
                explanation="NodePort exposes the service on a static port (30000-32767) on every Node's IP. You reach it at `<NodeIP>:<NodePort>` from outside the cluster.",
                xp=10,
            ),
            Challenge(
                id="k8s_ingress",
                type="quiz",
                prompt="What does a Kubernetes Ingress resource define?",
                options=[
                    "How Pods communicate with each other",
                    "HTTP/HTTPS routing rules from external traffic to internal Services",
                    "Network policies blocking traffic between namespaces",
                    "DNS records for cluster-external domains",
                ],
                answer="b",
                explanation="An Ingress defines rules for routing HTTP/HTTPS traffic from outside the cluster to Services. It requires an Ingress controller (like nginx) to implement the rules.",
                xp=10,
            ),
            Challenge(
                id="k8s_dns",
                type="fill_blank",
                prompt="A Service named `api` in namespace `backend` has the internal DNS: api.backend.svc._____",
                answer="cluster.local",
                explanation="Kubernetes DNS follows the pattern `<service>.<namespace>.svc.cluster.local`. The full domain ensures uniqueness across clusters.",
                xp=15,
                hints=["Standard cluster DNS suffix", "Three parts: cluster + local"],
            ),
            Challenge(
                id="k8s_port_forward",
                type="fill_blank",
                prompt="To access a Pod locally at port 8080 without a Service, use: kubectl port-_____ pod/my-pod 8080:80",
                answer="forward",
                explanation="`kubectl port-forward` tunnels traffic from your local machine to a Pod or Service. Useful for debugging without exposing services externally.",
                xp=15,
                hints=["You're forwarding a port", "Not port-tunnel or port-proxy"],
            ),
        ],
    ),
    "configmaps_and_secrets": Zone(
        id="configmaps_and_secrets",
        title="ConfigMaps and Secrets",
        description="Manage application configuration and sensitive data separately from container images.",
        challenges=[
            Challenge(
                id="k8s_configmap_purpose",
                type="quiz",
                prompt="What is the primary purpose of a Kubernetes ConfigMap?",
                options=[
                    "Store encrypted passwords and API keys",
                    "Decouple configuration data from container images",
                    "Define network policies for pods",
                    "Configure node resource limits",
                ],
                answer="b",
                explanation="ConfigMaps store non-sensitive configuration data (env vars, config files, command-line args) separately from images, making apps portable across environments.",
                url="https://kubernetes.io/docs/concepts/configuration/configmap/",
                xp=10,
            ),
            Challenge(
                id="k8s_secret_encoding",
                type="quiz",
                prompt="Kubernetes Secrets store values as base64. What does this mean for security?",
                options=[
                    "Values are encrypted at rest by default",
                    "Values are obfuscated but NOT encrypted — anyone with API access can read them",
                    "Values are hashed and irreversible",
                    "Values require a decryption key to view",
                ],
                answer="b",
                explanation="Base64 is encoding, not encryption. Secrets are obfuscated for transport but NOT secure by default. Use etcd encryption or external secret managers (Vault, AWS Secrets Manager) for real security.",
                xp=10,
            ),
            Challenge(
                id="k8s_env_from",
                type="quiz",
                prompt="To inject ALL keys from a ConfigMap as environment variables, you use:",
                options=[
                    "env.name: configMapRef",
                    "envFrom: - configMapRef: name: my-config",
                    "volumes.configMap: my-config",
                    "inject.configMap: all: true",
                ],
                answer="b",
                explanation="`envFrom` with `configMapRef` injects all ConfigMap keys as environment variables. Individual keys use `env` with `valueFrom.configMapKeyRef`.",
                xp=10,
            ),
            Challenge(
                id="k8s_secret_create",
                type="fill_blank",
                prompt="Create a generic secret from literal values: kubectl create secret _____ db-creds --from-literal=password=s3cr3t",
                answer="generic",
                explanation="The three secret types are `generic` (arbitrary key-value), `docker-registry` (image pull secrets), and `tls` (TLS cert/key pairs).",
                xp=15,
                hints=["It's for arbitrary key-value pairs", "Not 'tls' or 'docker-registry'"],
            ),
            Challenge(
                id="k8s_volume_mount",
                type="quiz",
                prompt="A ConfigMap contains a file `app.conf`. The best way to make it available inside a container is:",
                options=[
                    "Inject it as an environment variable",
                    "Mount it as a Volume at a path like /etc/config/app.conf",
                    "Encode it in the container's CMD",
                    "Store it in a Secret instead",
                ],
                answer="b",
                explanation="Files in ConfigMaps (or Secrets) are best mounted as Volumes. Each key becomes a file in the mount path. Env vars work for short strings but not for multi-line config files.",
                xp=10,
            ),
            Challenge(
                id="k8s_immutable_configmap",
                type="quiz",
                prompt="Setting `immutable: true` on a ConfigMap does what?",
                options=[
                    "Encrypts the ConfigMap data",
                    "Prevents the ConfigMap from being deleted",
                    "Prevents updates, improving cluster performance for large ConfigMaps",
                    "Makes the ConfigMap cluster-wide instead of namespace-scoped",
                ],
                answer="c",
                explanation="Immutable ConfigMaps/Secrets prevent accidental updates and allow the kubelet to stop watching them, reducing API server load. Useful for configs that should never change.",
                xp=15,
                hints=["It's about performance as well as safety"],
            ),
        ],
    ),
    "namespaces_and_rbac": Zone(
        id="namespaces_and_rbac",
        title="Namespaces and RBAC",
        description="Organize cluster resources and control access with Role-Based Access Control.",
        challenges=[
            Challenge(
                id="k8s_namespace_purpose",
                type="quiz",
                prompt="Kubernetes namespaces provide:",
                options=[
                    "Network isolation between Pods by default",
                    "A scope for names — the same resource name can exist in multiple namespaces",
                    "Guaranteed CPU and memory allocation",
                    "Encryption for all resources within them",
                ],
                answer="b",
                explanation="Namespaces partition the cluster's name space — two Deployments named `api` can exist in different namespaces. They don't provide network isolation by default (that's NetworkPolicy).",
                url="https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/",
                xp=10,
            ),
            Challenge(
                id="k8s_default_namespaces",
                type="quiz",
                prompt="Which namespace contains Kubernetes system components like kube-dns and kube-proxy?",
                options=["default", "kube-system", "kube-public", "cluster-admin"],
                answer="b",
                explanation="`kube-system` contains critical cluster components. `default` is for user workloads with no explicit namespace. `kube-public` is readable by all, used for cluster info.",
                xp=10,
            ),
            Challenge(
                id="k8s_rbac_role",
                type="quiz",
                prompt="What is the difference between a Role and a ClusterRole in RBAC?",
                options=[
                    "Roles have more permissions than ClusterRoles",
                    "A Role is namespace-scoped; a ClusterRole applies cluster-wide",
                    "ClusterRoles require multi-factor authentication",
                    "Roles use JSON; ClusterRoles use YAML",
                ],
                answer="b",
                explanation="Roles define permissions within a single namespace. ClusterRoles define permissions across the entire cluster (or for cluster-scoped resources like Nodes).",
                xp=10,
            ),
            Challenge(
                id="k8s_rolebinding",
                type="quiz",
                prompt="A RoleBinding connects:",
                options=[
                    "Two Services in different namespaces",
                    "A Role or ClusterRole to a user, group, or ServiceAccount",
                    "A Pod to its ConfigMap",
                    "A Deployment to its ReplicaSet",
                ],
                answer="b",
                explanation="A RoleBinding grants the permissions defined in a Role to a subject (user, group, or ServiceAccount). Without a binding, a Role has no effect.",
                xp=10,
            ),
            Challenge(
                id="k8s_service_account",
                type="fill_blank",
                prompt="Every Pod runs as a ServiceAccount. If not specified, it uses the _____ ServiceAccount in its namespace.",
                answer="default",
                explanation="The `default` ServiceAccount exists in every namespace. It's best practice to create dedicated ServiceAccounts with minimal permissions rather than using default.",
                xp=15,
                hints=["It's the most basic, unremarkable name"],
            ),
            Challenge(
                id="k8s_least_privilege",
                type="quiz",
                prompt="The principle of least privilege in RBAC means:",
                options=[
                    "Use ClusterAdmin for all service accounts to avoid permission errors",
                    "Grant only the minimum permissions needed to perform a function",
                    "Rotate service account tokens every hour",
                    "Disable RBAC for internal services",
                ],
                answer="b",
                explanation="Least privilege limits blast radius if a Pod is compromised. A compromised Pod with ClusterAdmin can destroy the entire cluster; one with read-only namespace permissions cannot.",
                xp=15,
                hints=["Less is more — for security"],
            ),
        ],
    ),
    "helm_charts": Zone(
        id="helm_charts",
        title="Helm Charts",
        description="Package, version, and deploy Kubernetes applications using the Helm package manager.",
        challenges=[
            Challenge(
                id="k8s_helm_purpose",
                type="quiz",
                prompt="What is Helm in the Kubernetes ecosystem?",
                options=[
                    "A monitoring tool for cluster metrics",
                    "A package manager that templates and manages Kubernetes manifests",
                    "A network policy engine",
                    "A container runtime alternative to Docker",
                ],
                answer="b",
                explanation="Helm is Kubernetes' package manager. It bundles related manifests into Charts, supports templating with values, and tracks release history for upgrades and rollbacks.",
                url="https://helm.sh/docs/intro/using_helm/",
                xp=10,
            ),
            Challenge(
                id="k8s_helm_install",
                type="fill_blank",
                prompt="Install a chart named `nginx-ingress` from the `ingress-nginx` repo with release name `ingress`: helm _____ ingress ingress-nginx/nginx-ingress",
                answer="install",
                explanation="`helm install <release-name> <chart>` deploys a chart. The release name identifies this specific installation and is used for upgrades and rollbacks.",
                xp=10,
            ),
            Challenge(
                id="k8s_helm_values",
                type="quiz",
                prompt="In a Helm chart, where are default configuration values defined?",
                options=["Chart.yaml", "values.yaml", "templates/deployment.yaml", "requirements.yaml"],
                answer="b",
                explanation="`values.yaml` holds default values that templates reference with `{{ .Values.key }}`. Users can override them with `--set key=value` or `-f custom-values.yaml`.",
                xp=10,
            ),
            Challenge(
                id="k8s_helm_upgrade",
                type="fill_blank",
                prompt="Update a running release to a new chart version: helm _____ my-app ./my-chart --set image.tag=v2.0",
                answer="upgrade",
                explanation="`helm upgrade` applies changes to an existing release. Combined with `--install`, it creates the release if it doesn't exist (`helm upgrade --install`).",
                xp=15,
                hints=["The opposite of 'downgrade'"],
            ),
            Challenge(
                id="k8s_helm_rollback",
                type="quiz",
                prompt="After a bad deployment, how do you revert to the previous Helm release?",
                options=[
                    "kubectl rollout undo deployment/my-app",
                    "helm revert my-release",
                    "helm rollback my-release",
                    "helm history my-release --revert",
                ],
                answer="c",
                explanation="`helm rollback <release> [revision]` reverts to a previous release revision. `helm history <release>` shows all revisions available to roll back to.",
                xp=15,
                hints=["Think of it like git rollback"],
            ),
            Challenge(
                id="k8s_helm_chart_yaml",
                type="quiz",
                prompt="The `Chart.yaml` file in a Helm chart contains:",
                options=[
                    "Kubernetes resource definitions",
                    "Template helper functions",
                    "Chart metadata: name, version, description, dependencies",
                    "Default configuration values",
                ],
                answer="c",
                explanation="`Chart.yaml` is the chart's metadata file — it defines the name, version, apiVersion, description, and dependencies (sub-charts). It's required for every Helm chart.",
                xp=10,
            ),
        ],
    ),
    "persistent_volumes": Zone(
        id="persistent_volumes",
        title="Persistent Volumes",
        description="Manage durable storage for stateful workloads using PVs, PVCs, and StorageClasses.",
        challenges=[
            Challenge(
                id="k8s_pv_purpose",
                type="quiz",
                prompt="Why does Kubernetes need Persistent Volumes (PVs) separate from Pods?",
                options=[
                    "Pods can't use disk storage at all",
                    "Container filesystems are ephemeral — data is lost when a Pod dies; PVs survive Pod restarts",
                    "PVs provide faster disk I/O than container filesystems",
                    "PVs are required for all Docker images",
                ],
                answer="b",
                explanation="Container filesystems are ephemeral — tied to the container lifecycle. When a Pod dies, all data written inside the container is gone. Persistent Volumes exist independently of Pods and survive restarts, rescheduling, and even Pod deletion.",
                url="https://kubernetes.io/docs/concepts/storage/persistent-volumes/",
                xp=10,
            ),
            Challenge(
                id="k8s_pvc",
                type="quiz",
                prompt="The relationship between a PersistentVolume (PV) and a PersistentVolumeClaim (PVC) is:",
                options=[
                    "They are the same thing — different names for the same resource",
                    "PV is the actual storage; PVC is a Pod's request for storage — the cluster binds a matching PV to the PVC",
                    "PVC is created by the admin; PV is created by the developer",
                    "PVs are for databases; PVCs are for file storage",
                ],
                answer="b",
                explanation="PV = the storage resource (provisioned by an admin or dynamically). PVC = a request for storage by a workload ('I need 10Gi, ReadWriteOnce'). Kubernetes binds a PVC to a matching PV. This separation lets developers request storage without knowing the underlying infrastructure.",
                xp=10,
            ),
            Challenge(
                id="k8s_storage_class",
                type="quiz",
                prompt="A StorageClass in Kubernetes enables:",
                options=[
                    "Manual provisioning of every PersistentVolume",
                    "Dynamic provisioning — PVs are automatically created when a PVC is submitted",
                    "Encryption of all volumes in a namespace",
                    "Backup scheduling for persistent data",
                ],
                answer="b",
                explanation="StorageClasses define provisioners (AWS EBS, GCP PD, etc.) and parameters. When a PVC references a StorageClass, Kubernetes automatically provisions a PV matching the request — no manual PV creation needed. This is the standard production pattern.",
                xp=10,
            ),
            Challenge(
                id="k8s_access_modes",
                type="quiz",
                prompt="A PVC with `accessMode: ReadWriteOnce` means:",
                options=[
                    "The volume can be read by all Pods simultaneously",
                    "The volume can be mounted read-write by only one Node at a time",
                    "The volume is read-only for all Pods",
                    "The volume can only be written to once and then becomes read-only",
                ],
                answer="b",
                explanation="ReadWriteOnce (RWO) means the volume can be mounted read-write by pods on a single node. ReadWriteMany (RWX) allows multiple nodes. For databases like PostgreSQL, RWO is correct — only one writer. NFS or distributed storage supports RWX.",
                xp=15,
                hints=["RWO = one node can write at a time"],
            ),
            Challenge(
                id="k8s_reclaim_policy",
                type="quiz",
                prompt="A PV has `reclaimPolicy: Delete`. When the bound PVC is deleted, the PV:",
                options=[
                    "Is retained and available for re-use",
                    "Is archived to S3 automatically",
                    "Is deleted along with the underlying storage",
                    "Moves to Released state and waits for a new claim",
                ],
                answer="c",
                explanation="Delete policy: PV and its underlying storage (EBS volume, GCP disk) are deleted when the PVC is deleted. Use Retain to preserve the data for manual recovery. For production databases, Retain is safer — Delete can cause irreversible data loss.",
                xp=15,
                hints=["The name says exactly what it does"],
            ),
            Challenge(
                id="k8s_statefulset_pvc",
                type="fill_blank",
                prompt="For stateful applications like databases that need stable storage per replica, use a _____ instead of a Deployment.",
                answer="StatefulSet",
                explanation="StatefulSets provide stable pod names (pod-0, pod-1), stable network identities, and ordered deployment. Each replica gets its own PVC via volumeClaimTemplates — pod-0 always gets its own PVC, never sharing with pod-1. Essential for clustered databases.",
                xp=15,
                hints=["It's the stateful counterpart to Deployment", "Starts with 'Stateful'"],
            ),
        ],
    ),
    "resource_management": Zone(
        id="resource_management",
        title="Resource Management",
        description="Control CPU and memory with requests, limits, HPA, and ResourceQuotas.",
        challenges=[
            Challenge(
                id="k8s_requests_limits",
                type="quiz",
                prompt="The difference between resource `requests` and `limits` in a Pod spec is:",
                options=[
                    "Requests are the minimum CPU/memory guaranteed; limits are the maximum the container can use",
                    "Requests are for CPU only; limits are for memory only",
                    "They are identical — just two names for the same field",
                    "Requests are set by developers; limits are set by cluster admins",
                ],
                answer="a",
                explanation="Requests tell the scheduler how much CPU/memory to reserve — the container is guaranteed at least this much. Limits are the ceiling — the container is killed if it exceeds the memory limit, or throttled if it exceeds CPU limit. Set both for predictable scheduling.",
                url="https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/",
                xp=10,
            ),
            Challenge(
                id="k8s_qos_classes",
                type="quiz",
                prompt="A Pod with equal requests and limits for all containers gets which QoS class?",
                options=["BestEffort", "Burstable", "Guaranteed", "Reserved"],
                answer="c",
                explanation="QoS classes: Guaranteed (requests == limits for all containers) → last to be evicted. Burstable (requests < limits, or only some containers have limits) → middle priority. BestEffort (no requests or limits) → first to be evicted under pressure.",
                xp=10,
            ),
            Challenge(
                id="k8s_hpa",
                type="quiz",
                prompt="A HorizontalPodAutoscaler (HPA) automatically:",
                options=[
                    "Increases the CPU limit of existing Pods under load",
                    "Adds or removes Pod replicas based on metrics like CPU utilization",
                    "Migrates Pods to nodes with more available memory",
                    "Upgrades the container image when a new version is available",
                ],
                answer="b",
                explanation="HPA scales the number of Pod replicas based on observed metrics. Configure: `min replicas`, `max replicas`, and target utilization (e.g., 70% CPU). When load increases, HPA adds Pods; when it decreases, it removes them. Requires the metrics-server.",
                xp=10,
            ),
            Challenge(
                id="k8s_resource_quota",
                type="fill_blank",
                prompt="To limit the total CPU and memory that all Pods in a namespace can consume, create a _____.",
                answer="ResourceQuota",
                explanation="ResourceQuota enforces namespace-level limits: total CPU requests, memory requests, number of Pods, PVCs, Services, etc. Without quotas, a single team can starve the entire cluster. Set quotas per namespace in multi-tenant clusters.",
                xp=15,
                hints=["It's a quota on resources", "Two words combined: Resource + Quota"],
            ),
            Challenge(
                id="k8s_limit_range",
                type="quiz",
                prompt="A LimitRange in a namespace sets:",
                options=[
                    "The total resources the namespace can consume",
                    "Default and maximum resource requests/limits for individual containers",
                    "The number of namespaces allowed per cluster",
                    "CPU frequency limits for worker nodes",
                ],
                answer="b",
                explanation="LimitRange sets defaults (applied when a container doesn't specify requests/limits) and max/min values per container, Pod, or PVC in a namespace. Pair with ResourceQuota: LimitRange sets per-container defaults; ResourceQuota sets namespace totals.",
                xp=10,
            ),
            Challenge(
                id="k8s_oom_kill",
                type="quiz",
                prompt="A container exceeds its memory limit. Kubernetes responds by:",
                options=[
                    "Throttling the container so it uses less memory",
                    "Migrating the Pod to a node with more memory",
                    "OOMKilling the container — killing it immediately",
                    "Increasing the memory limit automatically",
                ],
                answer="c",
                explanation="Memory limits are hard — there is no memory throttling in Linux. When a container exceeds its limit, the kernel's OOM killer terminates the process. The container restarts (if restartPolicy allows). CPU limits are soft — excess CPU is throttled, not killed.",
                xp=15,
                hints=["Memory is unforgiving — it kills, not throttles"],
            ),
        ],
    ),
    "network_policies": Zone(
        id="network_policies",
        title="Network Policies",
        description="Control traffic between Pods with NetworkPolicy rules — the cluster's firewall.",
        challenges=[
            Challenge(
                id="k8s_netpol_default",
                type="quiz",
                prompt="By default, what is the network policy for Pods in Kubernetes?",
                options=[
                    "All Pod-to-Pod traffic is blocked by default",
                    "Pods can only communicate within the same namespace",
                    "All Pods can communicate with all other Pods — no restrictions",
                    "Pods can only communicate through Services, never directly",
                ],
                answer="c",
                explanation="Kubernetes is open by default — all Pods can reach all other Pods across all namespaces. This is convenient but dangerous: a compromised Pod can reach every database, every internal API. NetworkPolicies add the firewall rules that should exist from the start.",
                url="https://kubernetes.io/docs/concepts/services-networking/network-policies/",
                xp=10,
            ),
            Challenge(
                id="k8s_netpol_selector",
                type="quiz",
                prompt="A NetworkPolicy selects which Pods it applies to using:",
                options=[
                    "Pod names (must match exactly)",
                    "Pod labels via `podSelector`",
                    "Namespace names",
                    "IP address CIDR ranges only",
                ],
                answer="b",
                explanation="NetworkPolicies use label selectors — `podSelector: matchLabels: app: backend` applies the policy to all Pods labeled `app: backend`. This is the same label-based selection used everywhere in Kubernetes.",
                xp=10,
            ),
            Challenge(
                id="k8s_netpol_default_deny",
                type="fill_blank",
                prompt="To block all ingress traffic to Pods in a namespace (a 'default deny' policy), create a NetworkPolicy with an empty `podSelector: {}` and no _____ rules.",
                answer="ingress",
                explanation="An empty podSelector (`{}`) selects ALL Pods in the namespace. A NetworkPolicy with no ingress rules blocks all ingress. This is the recommended baseline: default deny everything, then explicitly allow what's needed. Combine with an egress default-deny for defense in depth.",
                xp=15,
                hints=["You're denying incoming traffic", "Incoming = ingress, outgoing = egress"],
            ),
            Challenge(
                id="k8s_netpol_namespace",
                type="quiz",
                prompt="To allow traffic from Pods in namespace `monitoring` to reach Pods in namespace `finance`, the NetworkPolicy uses:",
                options=[
                    "A `podSelector` with the monitoring Pod names",
                    "A `namespaceSelector` with a label matching the monitoring namespace",
                    "An IP block CIDR covering the monitoring namespace subnet",
                    "A `serviceSelector` referencing the monitoring Service",
                ],
                answer="b",
                explanation="Cross-namespace policies use `namespaceSelector` — select namespaces by their labels (e.g., `kubernetes.io/metadata.name: monitoring`). Combine with `podSelector` for fine-grained control: only Pods with label `role: scraper` in the `monitoring` namespace.",
                xp=10,
            ),
            Challenge(
                id="k8s_netpol_egress",
                type="quiz",
                prompt="An egress NetworkPolicy on a Pod controls:",
                options=[
                    "Which Pods can send traffic TO this Pod",
                    "Which destinations this Pod can send traffic TO",
                    "How much bandwidth this Pod can use",
                    "Whether this Pod can be scheduled on specific nodes",
                ],
                answer="b",
                explanation="Egress policies restrict where a Pod can send traffic. A database Pod with a strict egress policy should only be able to reach its backup service, not arbitrary internet endpoints. Egress policies prevent data exfiltration from compromised containers.",
                xp=10,
            ),
            Challenge(
                id="k8s_netpol_cni",
                type="quiz",
                prompt="NetworkPolicies have no effect unless the cluster has a CNI plugin that enforces them. Which of these CNI plugins enforces NetworkPolicies?",
                options=[
                    "Flannel (basic overlay, does NOT enforce NetworkPolicy)",
                    "Calico (enforces NetworkPolicy and adds its own GlobalNetworkPolicy)",
                    "The kubelet enforces them — no CNI plugin is needed",
                    "All CNI plugins enforce NetworkPolicies",
                ],
                answer="b",
                explanation="NetworkPolicy is a Kubernetes API object, but enforcement requires the CNI plugin. Flannel, for example, does not enforce NetworkPolicies — your policies are accepted but silently ignored. Calico, Cilium, and Weave enforce them. Always verify your CNI supports NetworkPolicy.",
                xp=15,
                hints=["Not all CNI plugins are equal — check before deploying"],
            ),
        ],
    ),
    "cluster_troubleshooting": Zone(
        id="cluster_troubleshooting",
        title="Cluster Troubleshooting",
        description="Diagnose and fix failing Pods, stuck deployments, and misconfigured resources.",
        challenges=[
            Challenge(
                id="k8s_pod_pending",
                type="quiz",
                prompt="A Pod is stuck in `Pending` state. What is the most likely cause?",
                options=[
                    "The container image is crashing on startup",
                    "The Pod cannot be scheduled — insufficient resources or no matching node",
                    "The liveness probe is failing",
                    "The ConfigMap it references doesn't exist",
                ],
                answer="b",
                explanation="Pending means the scheduler can't place the Pod on a Node. Check `kubectl describe pod <name>` for events — common causes: insufficient CPU/memory, node selectors, taints.",
                url="https://kubernetes.io/docs/tasks/debug/debug-application/debug-pods/",
                xp=10,
            ),
            Challenge(
                id="k8s_crashloopbackoff",
                type="quiz",
                prompt="A Pod shows `CrashLoopBackOff`. This means:",
                options=[
                    "The Pod is waiting for a dependent service to start",
                    "The container starts, crashes, and Kubernetes keeps restarting it with delays",
                    "The Pod was evicted due to memory pressure",
                    "Network connectivity to the Pod is broken",
                ],
                answer="b",
                explanation="CrashLoopBackOff means the container is repeatedly crashing. Kubernetes backs off restart attempts exponentially. Check logs with `kubectl logs <pod> --previous` to see crash output.",
                xp=10,
            ),
            Challenge(
                id="k8s_logs",
                type="fill_blank",
                prompt="View logs from a crashed container's previous run: kubectl logs my-pod --_____",
                answer="previous",
                explanation="`--previous` (or `-p`) shows logs from the last terminated container instance — essential for debugging CrashLoopBackOff since the current container may have just started.",
                xp=15,
                hints=["You want the run before the current one"],
            ),
            Challenge(
                id="k8s_describe",
                type="quiz",
                prompt="Which command gives the most complete diagnostic view of a Pod including events?",
                options=[
                    "kubectl get pod my-pod -o yaml",
                    "kubectl logs my-pod",
                    "kubectl describe pod my-pod",
                    "kubectl inspect pod my-pod",
                ],
                answer="c",
                explanation="`kubectl describe` shows full resource details including Events — the 'Recent Events' section at the bottom shows scheduling failures, image pull errors, and probe failures.",
                xp=10,
            ),
            Challenge(
                id="k8s_exec",
                type="fill_blank",
                prompt="Run an interactive shell inside a running container: kubectl _____ -it my-pod -- /bin/sh",
                answer="exec",
                explanation="`kubectl exec -it <pod> -- <command>` runs a command inside a container. The `-it` flags attach an interactive terminal. Essential for live debugging.",
                xp=15,
                hints=["Like `docker exec`"],
            ),
            Challenge(
                id="k8s_oom",
                type="quiz",
                prompt="A Pod was killed with `OOMKilled` exit code. The fix is:",
                options=[
                    "Increase the Pod's CPU limit",
                    "Increase the Pod's memory limit or reduce memory usage",
                    "Add more replicas to the Deployment",
                    "Enable swap on the node",
                ],
                answer="b",
                explanation="OOMKilled means Out Of Memory — the container exceeded its memory limit. Either increase `resources.limits.memory` in the Pod spec or optimize the application's memory usage.",
                xp=15,
                hints=["OOM = Out Of Memory"],
            ),
        ],
    ),
    "statefulsets_and_daemonsets": {
        "id": "statefulsets_and_daemonsets",
        "name": "StatefulSets and DaemonSets",
        "description": "Ordered pod management for stateful apps and node-level workloads.",
        "challenges": [
            {
                "id": "k8s_statefulset_vs_deployment",
                "type": "quiz",
                "prompt": "You're deploying a Postgres database on Kubernetes. You need stable network identities (pod-0, pod-1) and persistent storage per pod. You use a:",
                "options": [
                    "Deployment — scale replicas freely, stateless approach",
                    "StatefulSet — provides stable pod names, ordered scaling, and per-pod PVCs",
                    "DaemonSet — runs one pod per node",
                    "ReplicaSet — manages pod replicas without ordering",
                ],
                "answer": "b",
                "explanation": "StatefulSets give each pod a stable ordinal identity (pod-0, pod-1) and a per-pod PersistentVolumeClaim that survives pod restarts. Pods start in order (0 → 1 → 2) and stop in reverse. Essential for distributed databases (Postgres, Cassandra, Kafka) where pod identity matters.",
                "xp": 15,
                "hints": ["The clue is 'stable network identities' and 'persistent storage per pod'"],
            },
            {
                "id": "k8s_statefulset_headless",
                "type": "quiz",
                "prompt": "StatefulSets typically use a Headless Service (clusterIP: None). This means DNS resolves to:",
                "options": [
                    "No DNS — StatefulSet pods communicate directly by IP",
                    "A single virtual IP load-balancing across all pods",
                    "Individual pod DNS names like pod-0.service.namespace.svc.cluster.local",
                    "The node IP of each pod's host",
                ],
                "answer": "c",
                "explanation": "A headless service (clusterIP: None) creates DNS records for each individual pod instead of a load-balancing VIP. This lets applications address specific pods directly — critical for clustered databases that need to know which replica is which.",
                "xp": 10,
                "hints": ["'Headless' means no cluster IP — DNS goes straight to pods"],
            },
            {
                "id": "k8s_daemonset",
                "type": "quiz",
                "prompt": "You need to run a log collector agent on every node in your cluster, including nodes added in the future. You use a:",
                "options": [
                    "Deployment with replicas equal to node count",
                    "StatefulSet with one replica per node",
                    "DaemonSet — automatically runs one pod per node",
                    "CronJob scheduled every minute",
                ],
                "answer": "c",
                "explanation": "DaemonSets ensure exactly one pod runs on each node. As nodes join the cluster, the DaemonSet automatically schedules a pod on them. Common uses: log collectors (Fluentd), metrics agents (Datadog), network plugins (Calico), and storage daemons.",
                "xp": 10,
                "hints": ["You want exactly one pod per node — automatically"],
            },
            {
                "id": "k8s_statefulset_scale",
                "type": "quiz",
                "prompt": "A StatefulSet with 3 replicas scales down to 1. Pods are terminated in what order?",
                "options": [
                    "Random order for fastest scale-down",
                    "Oldest first (pod-0 first)",
                    "Reverse ordinal order: pod-2 first, then pod-1",
                    "All simultaneously to minimize downtime",
                ],
                "answer": "c",
                "explanation": "StatefulSets scale down in reverse ordinal order — the highest ordinal terminates first. This ensures the cluster controller (usually pod-0) stays alive longest. Scale up goes 0 → 1 → 2; scale down goes 2 → 1 → 0.",
                "xp": 10,
                "hints": ["StatefulSets always do things in order — what's the reverse of 0,1,2?"],
            },
            {
                "id": "k8s_pvc_per_pod",
                "type": "fill_blank",
                "prompt": "In a StatefulSet, the field `volumeClaimTemplates` creates a separate _____ for each pod.",
                "answer": "PersistentVolumeClaim",
                "explanation": "Each StatefulSet pod gets its own PVC created from the volumeClaimTemplate. When a pod restarts on a new node, it reattaches to its original PVC — data persists. This is the key difference from Deployments where all pods share the same volumes.",
                "xp": 15,
                "hints": ["The per-pod storage object — starts with Persistent"],
            },
            {
                "id": "k8s_daemonset_toleration",
                "type": "quiz",
                "prompt": "A DaemonSet pod must run on control-plane nodes, which have the taint `node-role.kubernetes.io/control-plane:NoSchedule`. To schedule there, you add a:",
                "options": [
                    "NodeSelector matching the control-plane label",
                    "Toleration for the NoSchedule taint on the control-plane nodes",
                    "PriorityClass set to system-cluster-critical",
                    "Affinity rule preferring control-plane nodes",
                ],
                "answer": "b",
                "explanation": "Taints repel pods. To run on a tainted node you need a matching Toleration in the pod spec. Add `tolerations: [{key: 'node-role.kubernetes.io/control-plane', effect: NoSchedule}]` and the DaemonSet pod will schedule on control-plane nodes.",
                "xp": 15,
                "hints": ["Taints reject pods — you need to override that rejection with a ___"],
            },
        ],
    },
    "ingress_and_jobs": {
        "id": "ingress_and_jobs",
        "name": "Ingress and Jobs",
        "description": "HTTP routing into the cluster and batch workload management.",
        "challenges": [
            {
                "id": "k8s_ingress_purpose",
                "type": "quiz",
                "prompt": "You have 3 Services (api, frontend, auth) and want to expose them all under one external IP with path-based routing. You use:",
                "options": [
                    "Three separate LoadBalancer Services — one per app",
                    "A NodePort Service with manual port mapping",
                    "An Ingress resource with an Ingress Controller managing path rules",
                    "A Service of type ExternalName pointing to a cloud load balancer",
                ],
                "answer": "c",
                "explanation": "An Ingress resource defines HTTP routing rules (host/path → Service). An Ingress Controller (nginx, traefik, AWS ALB Ingress Controller) implements them — usually a single load balancer routes to multiple backends. Much cheaper and cleaner than one LoadBalancer Service per app.",
                "xp": 10,
                "hints": ["You need one entry point with routing rules — not one LB per service"],
            },
            {
                "id": "k8s_ingress_class",
                "type": "fill_blank",
                "prompt": "An Ingress resource specifies which controller handles it via the `ingressClassName` field or the `kubernetes.io/ingress.class: _____` annotation.",
                "answer": "nginx",
                "explanation": "Multiple Ingress Controllers can coexist. The `ingressClassName` field (or legacy annotation) tells Kubernetes which controller should handle a given Ingress. Common values: `nginx`, `traefik`, `alb` (AWS ALB Ingress Controller).",
                "xp": 10,
                "hints": ["The most common ingress controller — a well-known web server"],
            },
            {
                "id": "k8s_ingress_tls",
                "type": "quiz",
                "prompt": "To terminate TLS at the Ingress controller, you reference a Kubernetes _____ containing the certificate and private key.",
                "options": [
                    "ConfigMap with base64-encoded cert data",
                    "Secret of type kubernetes.io/tls with tls.crt and tls.key",
                    "PersistentVolume with the certificate files mounted",
                    "ServiceAccount with a bound certificate token",
                ],
                "answer": "b",
                "explanation": "TLS Secrets (type `kubernetes.io/tls`) hold `tls.crt` and `tls.key`. The Ingress spec's `tls` block references this Secret by name for each host. Cert-manager can auto-provision and rotate Let's Encrypt certificates into these Secrets.",
                "xp": 10,
                "hints": ["Certificates are stored as a specific type of Kubernetes Secret"],
            },
            {
                "id": "k8s_job",
                "type": "quiz",
                "prompt": "You need to run a one-time database migration that must complete successfully exactly once. You use a Kubernetes:",
                "options": [
                    "Pod — create and delete it manually after completion",
                    "Deployment with replicas: 1",
                    "Job — runs pods until the specified number of completions succeed, then stops",
                    "CronJob scheduled once at deployment time",
                ],
                "answer": "c",
                "explanation": "A Job manages pod completion. It runs pods until `completions` successful completions occur. If a pod fails, the Job creates a new one. Jobs are perfect for migrations, data imports, and batch processing — they succeed, then stop (unlike Deployments which run forever).",
                "xp": 10,
                "hints": ["It needs to run exactly once and succeed — what tracks completion?"],
            },
            {
                "id": "k8s_cronjob",
                "type": "fill_blank",
                "prompt": "A CronJob uses standard cron syntax. `0 */6 * * *` means: run every _____ hours.",
                "answer": "6",
                "explanation": "Standard cron: minute hour day month weekday. `0 */6 * * *` = at minute 0, every 6 hours. CronJobs create a Job at each scheduled time. Set `concurrencyPolicy: Forbid` to prevent overlapping runs if a previous Job is still running.",
                "xp": 10,
                "hints": ["*/6 in the hours field — divide into 24"],
            },
            {
                "id": "k8s_ingress_boss",
                "type": "quiz",
                "prompt": "NEXUS mission: route `nexus.internal/api/*` to the api Service and `nexus.internal/` to the frontend Service using a single Ingress. Traffic must be TLS-terminated. Which combination do you need?",
                "options": [
                    "One Ingress with two path rules, a TLS secret, and one Ingress Controller",
                    "Two separate Ingress resources, one per service, with separate load balancers",
                    "One Service of type LoadBalancer with path-based port mapping",
                    "A ConfigMap on the nginx pod with proxy_pass directives",
                ],
                "answer": "a",
                "explanation": "One Ingress resource can hold multiple path rules and a TLS spec. The Ingress Controller reads the rules and configures a single load balancer: HTTPS termination, path matching, backend routing to each Service. That's the correct architecture.",
                "xp": 15,
                "hints": ["One Ingress, two path rules, TLS block — the complete setup"],
            },
        ],
    },
}
