#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/test-common.sh"

REPLAY_PORT="${REPLAY_PORT:-19090}"
REPLAY_PHASES="${REPLAY_PHASES:-empty:45,error:45,data:90}"
REPLAY_WAIT_SECS="${REPLAY_WAIT_SECS:-210}"
METRICS_PORT_OFFSET="${METRICS_PORT_OFFSET:-700}"
DD_SITE="${DD_SITE:-datadoghq.com}"
DD_NAMESPACE="${DD_NAMESPACE:-chaos.test}"
RUN_ID="${RUN_ID:-chaos_$(date +%Y%m%d_%H%M%S)}"

if [[ -z "${DD_API_KEY:-}" ]]; then
  echo "❌ DD_API_KEY is required (use dedicated test key)"
  exit 1
fi

if [[ -z "${TENANT_ID:-}" || -z "${CLUSTER_ID_ESSENTIAL:-}" ]]; then
  echo "❌ TENANT_ID and CLUSTER_ID_ESSENTIAL are required in ${TEST_ENV_FILE}"
  exit 1
fi

OUT_DIR="${RESULTS_DIR}/chaos-dd/${RUN_ID}"
mkdir -p "${OUT_DIR}"

MOCK_LOG="${OUT_DIR}/mock-o11y.log"
PIPELINE_LOG="${OUT_DIR}/pipeline.log"
VECTOR_LOG="${OUT_DIR}/vector.log"
VECTOR_START_LOG="${OUT_DIR}/vector-start.log"
SUMMARY_TXT="${OUT_DIR}/summary.txt"

VECTOR_CONFIG_BASE="${CONFIG_ROOT}/vector/vector-dd-datadog.yaml"
OTEL_CONFIG_BASE="${CONFIG_ROOT}/otel/otel-config-dd.yaml"

tmp_vector_config=""
tmp_otel_config=""
tmp_metrics_config=""
mock_pid=""
pipeline_pid=""
container_name="vector-chaos-dd-${RUN_ID}"

cleanup() {
  set +e
  if [[ -n "${pipeline_pid}" ]]; then
    kill "${pipeline_pid}" >/dev/null 2>&1 || true
    wait "${pipeline_pid}" >/dev/null 2>&1 || true
  fi
  if [[ -n "${mock_pid}" ]]; then
    kill "${mock_pid}" >/dev/null 2>&1 || true
    wait "${mock_pid}" >/dev/null 2>&1 || true
  fi
  docker logs "${container_name}" > "${VECTOR_LOG}" 2>&1 || true
  docker stop "${container_name}" >/dev/null 2>&1 || true
  docker rm "${container_name}" >/dev/null 2>&1 || true
  [[ -n "${tmp_vector_config}" ]] && rm -f "${tmp_vector_config}"
  [[ -n "${tmp_otel_config}" ]] && rm -f "${tmp_otel_config}"
  [[ -n "${tmp_metrics_config}" ]] && rm -f "${tmp_metrics_config}"
}
trap cleanup EXIT INT TERM

wait_http_ok() {
  local url="$1"
  local sec="${2:-30}"
  local i
  for i in $(seq 1 "${sec}"); do
    if curl -sf "${url}" >/dev/null 2>&1; then
      return 0
    fi
    sleep 1
  done
  return 1
}

wait_port_open() {
  local host="$1"
  local port="$2"
  local sec="${3:-30}"
  local i
  for i in $(seq 1 "${sec}"); do
    if python3 - <<'PY' "$host" "$port" >/dev/null 2>&1
import socket, sys
host = sys.argv[1]
port = int(sys.argv[2])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1.0)
try:
    s.connect((host, port))
    ok = True
except Exception:
    ok = False
finally:
    s.close()
raise SystemExit(0 if ok else 1)
PY
    then
      return 0
    fi
    sleep 1
  done
  return 1
}

mktemp_yaml() {
  if mktemp --help 2>/dev/null | grep -q -- '--suffix'; then
    mktemp --suffix=.yaml
  else
    local tmp
    tmp=$(mktemp -t local-e2e.XXXXXXXXXX)
    mv "${tmp}" "${tmp}.yaml"
    echo "${tmp}.yaml"
  fi
}

# 1) Prepare binaries/configs
if [[ ! -x "${GENERATED_BIN_DIR}/metrics-collector-feature" ]]; then
  echo "[prep] feature binary missing, building..."
  (cd "${REPO_ROOT}/pipeline" && CGO_ENABLED=0 go build -o "${GENERATED_BIN_DIR}/metrics-collector-feature" cmd/metrics-collector/main.go)
fi

if [[ ! -f "${GENERATED_CONFIG_DIR}/metrics-config-Essential-${CLUSTER_ID_ESSENTIAL}.yaml" ]]; then
  echo "[prep] generated metrics config missing, running gen-configs.sh..."
  bash "${SCRIPT_DIR}/gen-configs.sh"
fi

# 2) Start mock o11y server
python3 "${SCRIPT_DIR}/mock_o11y_server.py" \
  --port "${REPLAY_PORT}" \
  --phases "${REPLAY_PHASES}" \
  --cluster-id "${CLUSTER_ID_ESSENTIAL}" \
  --tenant-id "${TENANT_ID}" \
  --project-id "${PROJECT_ID_ESSENTIAL:-0}" \
  --vendor "${CLUSTER_CLOUD_PROVIDER_ESSENTIAL:-${CLUSTER_CLOUD_PROVIDER}}" \
  --region "${CLUSTER_REGION_ESSENTIAL:-${CLUSTER_REGION}}" \
  --run-id "${RUN_ID}" \
  > "${MOCK_LOG}" 2>&1 &
mock_pid=$!

wait_http_ok "http://127.0.0.1:${REPLAY_PORT}/healthz" 20 || {
  echo "❌ mock server not ready"
  exit 1
}

# 3) Render vector config (real Datadog sink)
tmp_vector_config=$(mktemp_yaml)
python3 - <<'PY' "${VECTOR_CONFIG_BASE}" "${tmp_vector_config}" "${DD_API_KEY}" "${DD_SITE}"
import sys
src, dst, key, site = sys.argv[1:]
text = open(src, 'r', encoding='utf-8').read()
text = text.replace('__DD_API_KEY__', key).replace('__DD_SITE__', site)
open(dst, 'w', encoding='utf-8').write(text)
PY

# 4) Render otel config (to local vector port 14318)
tmp_otel_config=$(mktemp_yaml)
cp "${OTEL_CONFIG_BASE}" "${tmp_otel_config}"

# 5) Render metrics config (route global/regional to mock)
tmp_metrics_config=$(mktemp_yaml)
cp "${GENERATED_CONFIG_DIR}/metrics-config-Essential-${CLUSTER_ID_ESSENTIAL}.yaml" "${tmp_metrics_config}"
python3 - <<'PY' "${tmp_metrics_config}" "${REPLAY_PORT}" "${METRICS_PORT_OFFSET}"
import re
import sys
p, port, offset = sys.argv[1], sys.argv[2], int(sys.argv[3])
text = open(p, 'r', encoding='utf-8').read()
text = text.replace('grpcPort: 10000', f'grpcPort: {10000 + offset}')
text = text.replace('metricsPort: 9090', f'metricsPort: {9090 + offset}')
text = text.replace('metricsListenAddr: 0.0.0.0:8080', f'metricsListenAddr: 0.0.0.0:{8080 + offset}')

# Force local test routing to mock server regardless existing values.
text = re.sub(r'localTestEnabled:\s*(true|false)', 'localTestEnabled: true', text)
text = re.sub(r"localTestGlobalServerUrl:\s*'[^']*'", f"localTestGlobalServerUrl: 'http://127.0.0.1:{port}'", text)
text = re.sub(r"localTestRegionalServerUrl:\s*'[^']*'", f"localTestRegionalServerUrl: 'http://127.0.0.1:{port}'", text)

# Override any per-plan mapping URLs to the same mock endpoint.
text = re.sub(r"(url:\s*)'[^']*'", rf"\1'http://127.0.0.1:{port}'", text)

open(p, 'w', encoding='utf-8').write(text)
PY

# 6) Start vector

docker stop "${container_name}" >/dev/null 2>&1 || true
docker rm "${container_name}" >/dev/null 2>&1 || true

docker run -d \
  --name "${container_name}" \
  -p 14317:14317 \
  -p 14318:14318 \
  -p 8686:8686 \
  -v "${tmp_vector_config}:/etc/vector/vector.yaml:ro" \
  timberio/vector:0.47.0-debian \
  --config /etc/vector/vector.yaml \
  > "${VECTOR_START_LOG}" 2>&1

container_id="$(cat "${VECTOR_START_LOG}" 2>/dev/null || true)"
if [[ -n "${container_id}" ]]; then
  echo "vector container id: ${container_id}" >> "${VECTOR_START_LOG}"
fi

wait_port_open "127.0.0.1" 14318 30 || {
  echo "❌ vector not ready"
  echo "vector-start log:"
  cat "${VECTOR_START_LOG}" || true
  echo "docker ps -a snapshot:" >> "${VECTOR_START_LOG}"
  docker ps -a --format '{{.ID}} {{.Names}} {{.Status}}' >> "${VECTOR_START_LOG}" 2>&1 || true
  echo "vector container logs:" >> "${VECTOR_START_LOG}"
  docker logs "${container_name}" >> "${VECTOR_START_LOG}" 2>&1 || true
  exit 1
}

# 7) Start pipeline
"${GENERATED_BIN_DIR}/metrics-collector-feature" \
  --config "${tmp_otel_config}" \
  --metrics-config "${tmp_metrics_config}" \
  > "${PIPELINE_LOG}" 2>&1 &
pipeline_pid=$!

# 8) Run replay window
sleep "${REPLAY_WAIT_SECS}"

# 9) Stop components (trap will do final cleanup)
kill "${pipeline_pid}" >/dev/null 2>&1 || true
wait "${pipeline_pid}" >/dev/null 2>&1 || true
pipeline_pid=""

python3 - <<'PY' "${SUMMARY_TXT}" "${PIPELINE_LOG}" "${RUN_ID}" "${DD_NAMESPACE}" "${REPLAY_WAIT_SECS}" "${REPLAY_PHASES}"
import sys
summary_path, pipeline_log, run_id, namespace, wait_secs, phases = sys.argv[1:]

requeue = 0
empty = 0
qerr = 0
with open(pipeline_log, 'r', encoding='utf-8', errors='ignore') as f:
    for line in f:
        if 'task failed, should be requeue and re-execute' in line:
            requeue += 1
        if 'no datapoint exists, should requeue and wait' in line:
            empty += 1
        if 'failed to call queryFunc' in line:
            qerr += 1

with open(summary_path, 'w', encoding='utf-8') as f:
    f.write(f'run_id={run_id}\n')
    f.write(f'phase={phases}\n')
    f.write(f'wait_secs={wait_secs}\n')
    f.write(f'requeue_count={requeue}\n')
    f.write(f'empty_count={empty}\n')
    f.write(f'query_error_count={qerr}\n\n')
    f.write('Datadog verify hints:\n')
    f.write(f'- metric namespace: {namespace}\n')
    f.write(f'- filter tags include: chaos_run:{run_id}\n')
    f.write(f'- check gap/recovery around now()-{wait_secs}s to now\n')
PY

echo "✅ chaos replay done"
echo "run_id: ${RUN_ID}"
echo "summary: ${SUMMARY_TXT}"
echo "pipeline log: ${PIPELINE_LOG}"
echo "mock log: ${MOCK_LOG}"
