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

readonly SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
readonly MARKER="${SCRIPT_DIR}/.sys-l-203-vm"
readonly SNAPSHOT_FILE="${SCRIPT_DIR}/.vm-snapshot-confirmation"
readonly WORK_DIR="${SCRIPT_DIR}/work"

die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
validate_snapshot() {
  [[ -f "${SNAPSHOT_FILE}" && ! -L "${SNAPSHOT_FILE}" ]] ||
    die "falta .vm-snapshot-confirmation; crea el snapshot real y registra VM y snapshot"
  local -a metadata=()
  mapfile -t metadata <"${SNAPSHOT_FILE}"
  [[ "${#metadata[@]}" -eq 2 ]] || die "la confirmación debe contener exactamente vm= y snapshot="
  [[ "${metadata[0]}" =~ ^vm=[A-Za-z0-9][A-Za-z0-9._-]{1,63}$ ]] ||
    die "nombre de VM inválido en la confirmación"
  [[ "${metadata[1]}" =~ ^snapshot=[A-Za-z0-9][A-Za-z0-9._-]{1,63}$ ]] ||
    die "nombre de snapshot inválido en la confirmación"
}
validate() {
  [[ "${EUID}" -ne 0 ]] || die "ejecuta como usuario ordinario dentro de la VM"
  [[ -f "${MARKER}" ]] || die "falta el marcador del fixture"
  [[ "$(cat "${MARKER}")" == "SYS-L-203 fixture v1" ]] || die "marcador inesperado"
  validate_snapshot
  mkdir -p -- "${WORK_DIR}"
}
preflight() {
  validate
  local available_kib vm_name snapshot_name
  available_kib="$(df -Pk "${WORK_DIR}" | awk 'NR==2 {print $4}')"
  [[ "${available_kib}" =~ ^[0-9]+$ ]] || die "no se pudo medir espacio"
  (( available_kib >= 1048576 )) || die "se requiere al menos 1 GiB libre dentro de la VM"
  vm_name="$(sed -n 's/^vm=//p' "${SNAPSHOT_FILE}")"
  snapshot_name="$(sed -n 's/^snapshot=//p' "${SNAPSHOT_FILE}")"
  printf 'lab=SYS-L-203 vm=%s snapshot=%s directory=%s free_kib=%s\n' \
    "${vm_name}" "${snapshot_name}" "${SCRIPT_DIR}" "${available_kib}"
}
baseline() {
  validate
  date -u +%FT%TZ
  free -h
  vmstat 1 3
  df -h "${WORK_DIR}"
}
cpu_load() {
  validate
  timeout 12s sh -c 'while :; do sha256sum /dev/zero >/dev/null; done' || [[ "$?" -eq 124 ]]
}
memory_load() {
  validate
  timeout 12s python3 -c 'import time; payload=bytearray(256*1024*1024); payload[::4096]=b"x"*(len(payload)//4096); time.sleep(10)' || [[ "$?" -eq 124 ]]
}
io_load() {
  preflight
  timeout 20s dd if=/dev/zero of="${WORK_DIR}/io.bin" bs=1M count=256 conv=fsync status=progress
  rm -f -- "${WORK_DIR}/io.bin"
}
reset() {
  validate
  local resolved
  resolved="$(realpath -m "${WORK_DIR}")"
  [[ "${resolved}" == "${SCRIPT_DIR}/work" ]] || die "ruta de reset fuera del paquete"
  rm -f -- "${WORK_DIR}/io.bin"
  rmdir -- "${WORK_DIR}" 2>/dev/null || true
  printf 'reset=complete\n'
}
case "${1:-}" in
  preflight) preflight ;;
  baseline) baseline ;;
  cpu) cpu_load ;;
  memory) memory_load ;;
  io) io_load ;;
  reset) reset ;;
  *) die "uso: ./lab {preflight|baseline|cpu|memory|io|reset}" ;;
esac
