#!/usr/bin/env bash
# Verify the capacity-planner Helm chart without touching a cluster:
# strict lint, default render (with CRDs), CRD byte-equality with the
# controller-gen output, and render assertions (deployment safety args,
# active reconciler RBAC, no Service / ValidatingWebhook).
#
# Run from the module root (internal/capacity-planner).
set -euo pipefail

HELM=${HELM:-bin/helm}
CHART=charts/capacity-planner
CRD_SRC=config/crd/bases/autoscaling.pingcap.com_autoscalers.yaml
CRD_CHART=$CHART/crds/autoscaling.pingcap.com_autoscalers.yaml
RENDER_DIR=$(mktemp -d)
trap 'rm -rf "$RENDER_DIR"' EXIT

"$HELM" lint "$CHART" --strict

"$HELM" template "$CHART" --include-crds > "$RENDER_DIR/all.yaml"
"$HELM" template "$CHART" --set config.records.dir=/var/lib/capacity-planner/records > "$RENDER_DIR/records.yaml"

# CRD must be byte-identical to the controller-gen output (manifests target
# runs before this script via make verify/chart).
cmp "$CRD_SRC" "$CRD_CHART"

# Deployment passes only the two independent configuration files.
for arg in "--config=/etc/capacity-planner/capacity-planner.yaml" "--tier-templates-config=/etc/capacity-planner/tier-templates.yaml"; do
  if ! grep -q -- "$arg" "$RENDER_DIR/all.yaml"; then
    echo "helm-verify: rendered Deployment is missing required arg $arg" >&2
    exit 1
  fi
done
if ! grep -q 'mountPath: /var/lib/capacity-planner/records' "$RENDER_DIR/all.yaml"; then
  echo "helm-verify: decision records must be enabled by default" >&2
  exit 1
fi
if ! grep -A3 'name: metrics-storage' "$RENDER_DIR/all.yaml" | grep -q 'sizeLimit: 2Gi'; then
  echo "helm-verify: metrics emptyDir is missing its size limit" >&2
  exit 1
fi
if ! grep -A3 'name: decision-records' "$RENDER_DIR/records.yaml" | grep -q 'sizeLimit: 2Gi'; then
  echo "helm-verify: decision-records emptyDir is missing its size limit" >&2
  exit 1
fi
if ! grep -q 'mountPath: /var/lib/capacity-planner/records' "$RENDER_DIR/records.yaml"; then
  echo "helm-verify: records.dir does not control the decision-records mount" >&2
  exit 1
fi
for legacy_arg in --leader-elect --metrics-bind-address --health-probe-bind-address --sync-period --metrics-scrape-interval --pod-metrics-scrape --metrics-storage-path --metrics-retention --metrics-query --decision-records-dir --zap-; do
  if grep -q -- "$legacy_arg" "$RENDER_DIR/all.yaml"; then
    echo "helm-verify: runtime setting is still passed as legacy arg $legacy_arg" >&2
    exit 1
  fi
done

# No Service and no ValidatingWebhookConfiguration (handlers are not served).
if ! grep -q "^kind: ConfigMap$" "$RENDER_DIR/all.yaml"; then
  echo "helm-verify: chart must render a tier templates ConfigMap" >&2
  exit 1
fi
if ! grep -q "tidbcloud.com/node-spec" "$RENDER_DIR/all.yaml"; then
  echo "helm-verify: tier templates ConfigMap is missing node-spec template" >&2
  exit 1
fi
if ! grep -q "capacity-planner.yaml: |-" "$RENDER_DIR/all.yaml" ||
  ! grep -q "kind: CapacityPlannerConfiguration" "$RENDER_DIR/all.yaml" ||
  ! grep -q -- "- tidb_server_query_total" "$RENDER_DIR/all.yaml" ||
  ! grep -q -- "record: pod:tidb_server_query:rate1m" "$RENDER_DIR/all.yaml" ||
  ! grep -q -- "sum by (namespace, group, component, pod)" "$RENDER_DIR/all.yaml"; then
  echo "helm-verify: runtime config is missing the TiDB QPS scrape and recording rule" >&2
  exit 1
fi
runtime_config="$(sed -n '/^  capacity-planner.yaml: |-$/,/^  tier-templates.yaml: |-$/p' "$RENDER_DIR/all.yaml")"
rules_config="$(awk '/^    rules:$/ {found=1; print; next} found && /^    scrapers:$/ {exit} found {print}' <<< "$runtime_config")"
for ignored_label in type result resource_group; do
  if grep -Eq "(^|[^[:alnum:]_])${ignored_label}([^[:alnum:]_]|$)" <<< "$rules_config"; then
    echo "helm-verify: TiDB QPS recording rule must aggregate away $ignored_label" >&2
    exit 1
  fi
done
metrics_config="$(awk '/^    metrics:$/ {found=1; print; next} found && /^    [[:alnum:]][[:alnum:]]*:/ {exit} found {print}' <<< "$runtime_config")"
if [[ "$metrics_config" != $'    metrics:\n      bindAddress: "0"' ]]; then
  echo "helm-verify: metrics must configure only the planner self-metrics endpoint" >&2
  exit 1
fi

if grep -q "^kind: Service$" "$RENDER_DIR/all.yaml"; then
  echo "helm-verify: chart must not render a Service" >&2
  exit 1
fi
if grep -q "ValidatingWebhookConfiguration" "$RENDER_DIR/all.yaml"; then
  echo "helm-verify: chart must not render a ValidatingWebhookConfiguration" >&2
  exit 1
fi

# The Autoscaler ClusterRole must grant only the active reconciler's required
# API surface. Only inspect that role, not the Lease Role (which legitimately
# needs create/update/patch).
awk '/^kind: ClusterRole$/{flag=1} flag{print} /^---$/{if (flag) exit}' "$RENDER_DIR/all.yaml" > "$RENDER_DIR/clusterrole.yaml"
if ! grep -q "autoscalers" "$RENDER_DIR/clusterrole.yaml"; then
  echo "helm-verify: Autoscaler ClusterRole is missing autoscalers resource" >&2
  exit 1
fi
for verb in get list watch; do
  if ! awk '/resources: \["autoscalers"\]/{flag=1} flag && /verbs:/{print; exit}' "$RENDER_DIR/clusterrole.yaml" | grep -q "$verb"; then
    echo "helm-verify: Autoscaler ClusterRole must grant verb $verb" >&2
    exit 1
  fi
done

for resource in tidbgroups tikvgroups tikvworkergroups tiflashgroups tiproxygroups ticdcgroups pdgroups tsogroups schedulinggroups schedulergroups resourcemanagergroups; do
  if ! grep -q -- "- $resource" "$RENDER_DIR/clusterrole.yaml"; then
    echo "helm-verify: Autoscaler ClusterRole is missing target resource $resource" >&2
    exit 1
  fi
done
target_verbs=$(awk '/resources:/{flag=1} flag && /tidbgroups/{target=1} target && /verbs:/{print; exit}' "$RENDER_DIR/clusterrole.yaml")
for verb in get patch; do
	if ! grep -q "$verb" <<< "$target_verbs"; then
		echo "helm-verify: Autoscaler ClusterRole must grant verb $verb on target groups" >&2
		exit 1
	fi
done

if ! grep -q 'resources: \["customresourcedefinitions"\]' "$RENDER_DIR/clusterrole.yaml"; then
	echo "helm-verify: Autoscaler ClusterRole must read target CRD schemas" >&2
	exit 1
fi
for resource in tidbgroups.core.pingcap.com tikvgroups.core.pingcap.com tikvworkergroups.core.pingcap.com tiflashgroups.core.pingcap.com tiproxygroups.core.pingcap.com ticdcgroups.core.pingcap.com pdgroups.core.pingcap.com tsogroups.core.pingcap.com schedulinggroups.core.pingcap.com schedulergroups.core.pingcap.com resourcemanagergroups.core.pingcap.com; do
	if ! grep -q -- "- $resource" "$RENDER_DIR/clusterrole.yaml"; then
		echo "helm-verify: Autoscaler ClusterRole is missing target CRD $resource" >&2
		exit 1
	fi
done
if ! awk '/resources: \["customresourcedefinitions"\]/{crds=1} crds && /verbs:/{print; exit}' "$RENDER_DIR/clusterrole.yaml" | grep -q "get"; then
	echo "helm-verify: Autoscaler ClusterRole must get target CRDs" >&2
	exit 1
fi

core_pod_verbs=$(awk '/apiGroups: \[""\]/{core=1} core && /resources: \["pods"\]/{pods=1} pods && /verbs:/{print; exit}' "$RENDER_DIR/clusterrole.yaml")
for verb in get list watch; do
  if ! grep -q "$verb" <<< "$core_pod_verbs"; then
    echo "helm-verify: Autoscaler ClusterRole must grant verb $verb on core pods" >&2
    exit 1
  fi
done
if ! awk '/apiGroups: \["metrics.k8s.io"\]/{metrics=1} metrics && /resources: \["pods"\]/{pods=1} pods && /verbs:/{print; exit}' "$RENDER_DIR/clusterrole.yaml" | grep -q "list"; then
  echo "helm-verify: Autoscaler ClusterRole must list PodMetrics" >&2
  exit 1
fi

# controller-runtime emits an Event in the release namespace after acquiring
# the leader lease. Keep this permission namespaced instead of widening the
# reconciler ClusterRole.
awk '/^kind: Role$/{flag=1} flag{print} /^---$/{if (flag) exit}' "$RENDER_DIR/all.yaml" > "$RENDER_DIR/role.yaml"
event_verbs=$(awk '/resources: \["events"\]/{events=1} events && /verbs:/{print; exit}' "$RENDER_DIR/role.yaml")
for verb in create patch; do
  if ! grep -q "$verb" <<< "$event_verbs"; then
    echo "helm-verify: leader-election Role must grant verb $verb on core events" >&2
    exit 1
  fi
done

for verb in create update delete; do
  if awk '/^kind: ClusterRole$/{flag=1} flag{print} /^---$/{if (flag) exit}' "$RENDER_DIR/all.yaml" | grep -q "$verb"; then
    echo "helm-verify: Autoscaler ClusterRole must not grant verb $verb" >&2
    exit 1
  fi
done

echo "verify/chart: OK (lint, render, CRD equality, active RBAC assertions)"
