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

readonly LAB_ID="SYS-L-101"
readonly LAB_SLUG="sys-l-101"
readonly OWNERSHIP_LABEL="io.kiril-ferrer.learning.lab"
readonly SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
readonly ATTEMPT_FILE="${SCRIPT_DIR}/.attempt-id"

die() {
  printf 'ERROR: %s\n' "$*" >&2
  exit 1
}

require_file() {
  local target="$1"
  [[ -f "$target" ]] || die "Falta el archivo requerido: $target"
}

require_non_root() {
  [[ "$(id -u)" -ne 0 ]] || die "Ejecuta este laboratorio como usuario normal, sin sudo."
}

choose_engine() {
  local requested="${SYS_LAB_ENGINE:-}"

  if [[ -n "$requested" ]]; then
    [[ "$requested" == "podman" || "$requested" == "docker" ]] \
      || die "SYS_LAB_ENGINE solo admite 'podman' o 'docker'."
    command -v "$requested" >/dev/null 2>&1 \
      || die "No se encontró el runtime solicitado: $requested"
    printf '%s\n' "$requested"
    return
  fi

  if command -v podman >/dev/null 2>&1; then
    printf 'podman\n'
    return
  fi

  if command -v docker >/dev/null 2>&1; then
    printf 'docker\n'
    return
  fi

  die "Necesitas Podman rootless, Docker rootless o Docker Desktop."
}

assert_safe_runtime() {
  local engine="$1"
  local rootless=""
  local security_options=""
  local operating_system=""

  "$engine" info >/dev/null 2>&1 \
    || die "El runtime '$engine' no responde para el usuario actual."

  if [[ "$engine" == "podman" ]]; then
    rootless="$("$engine" info --format '{{.Host.Security.Rootless}}' 2>/dev/null || true)"
    [[ "$rootless" == "true" ]] \
      || die "Podman debe ejecutarse en modo rootless para este laboratorio."
    return
  fi

  security_options="$("$engine" info --format '{{json .SecurityOptions}}' 2>/dev/null || true)"
  operating_system="$("$engine" info --format '{{.OperatingSystem}}' 2>/dev/null || true)"
  if [[ "$security_options" == *rootless* || "$operating_system" == *"Docker Desktop"* ]]; then
    return
  fi

  die "Docker no informa modo rootless ni Docker Desktop. No continúes con sudo."
}

ensure_attempt_id() {
  if [[ ! -f "$ATTEMPT_FILE" ]]; then
    umask 077
    printf '%s-%s\n' "$(date -u +%Y%m%dT%H%M%SZ)" "$$" > "$ATTEMPT_FILE"
  fi
}

attempt_id() {
  ensure_attempt_id
  local value=""
  IFS= read -r value < "$ATTEMPT_FILE"
  [[ "$value" =~ ^[A-Za-z0-9][A-Za-z0-9._-]{5,63}$ ]] \
    || die "El attempt ID no cumple el formato seguro."
  printf '%s\n' "$value"
}

container_name() {
  printf '%s-%s\n' "$LAB_SLUG" "$(attempt_id)"
}

image_name() {
  printf 'localhost/%s:%s\n' "$LAB_SLUG" "$(attempt_id)"
}

container_exists() {
  local engine="$1"
  "$engine" inspect "$(container_name)" >/dev/null 2>&1
}

image_exists() {
  local engine="$1"
  "$engine" image inspect "$(image_name)" >/dev/null 2>&1
}

assert_owned_container() {
  local engine="$1"
  local actual=""
  actual="$("$engine" inspect \
    --format "{{ index .Config.Labels \"${OWNERSHIP_LABEL}\" }}" \
    "$(container_name)" 2>/dev/null || true)"
  if [[ -z "$actual" ]]; then
    actual="$("$engine" inspect \
      --format "{{ index .Labels \"${OWNERSHIP_LABEL}\" }}" \
      "$(container_name)" 2>/dev/null || true)"
  fi
  [[ "$actual" == "$LAB_ID" ]] \
    || die "El contenedor encontrado no pertenece a este intento; no se modificará."
}

assert_owned_image() {
  local engine="$1"
  local actual=""
  actual="$("$engine" image inspect \
    --format "{{ index .Config.Labels \"${OWNERSHIP_LABEL}\" }}" \
    "$(image_name)" 2>/dev/null || true)"
  if [[ -z "$actual" ]]; then
    actual="$("$engine" image inspect \
      --format "{{ index .Labels \"${OWNERSHIP_LABEL}\" }}" \
      "$(image_name)" 2>/dev/null || true)"
  fi
  [[ "$actual" == "$LAB_ID" ]] \
    || die "La imagen encontrada no pertenece a este intento; no se modificará."
}

endpoint() {
  local engine="$1"
  local binding=""
  container_exists "$engine" || die "El intento no está iniciado."
  assert_owned_container "$engine"
  binding="$("$engine" port "$(container_name)" 8080/tcp | tail -n 1)"
  [[ "$binding" =~ ^127\.0\.0\.1:[0-9]+$ ]] \
    || die "El puerto no está ligado exclusivamente a loopback: $binding"
  printf 'http://%s\n' "$binding"
}

doctor() {
  local engine="$1"
  require_non_root
  require_file "${SCRIPT_DIR}/Containerfile"
  require_file "${SCRIPT_DIR}/app.py"
  command -v curl >/dev/null 2>&1 || die "Se necesita curl en el host."
  assert_safe_runtime "$engine"
  printf 'Lab: %s\n' "$LAB_ID"
  printf 'Runtime: %s\n' "$engine"
  printf 'Attempt ID: %s\n' "$(attempt_id)"
  printf 'Directorio: %s\n' "$SCRIPT_DIR"
  printf 'Aislamiento: runtime aceptado; ejecución sin sudo\n'
}

start() {
  local engine="$1"
  local container=""
  local image=""
  local lab_endpoint=""

  doctor "$engine"
  container="$(container_name)"
  image="$(image_name)"

  if container_exists "$engine"; then
    assert_owned_container "$engine"
    if [[ "$("$engine" inspect --format '{{.State.Running}}' "$container")" == "true" ]]; then
      printf 'El intento ya está en ejecución: %s\n' "$container"
      endpoint "$engine"
      return
    fi
    "$engine" start "$container" >/dev/null
  else
    "$engine" build \
      --label "${OWNERSHIP_LABEL}=${LAB_ID}" \
      --label "${OWNERSHIP_LABEL}.attempt=$(attempt_id)" \
      --tag "$image" \
      --file "${SCRIPT_DIR}/Containerfile" \
      "$SCRIPT_DIR"

    "$engine" run --detach \
      --name "$container" \
      --label "${OWNERSHIP_LABEL}=${LAB_ID}" \
      --label "${OWNERSHIP_LABEL}.attempt=$(attempt_id)" \
      --read-only \
      --tmpfs /tmp:rw,noexec,nosuid,size=16m \
      --cap-drop ALL \
      --security-opt no-new-privileges \
      --pids-limit 64 \
      --memory 128m \
      --cpus 0.50 \
      --publish 127.0.0.1::8080 \
      "$image" >/dev/null
  fi

  lab_endpoint="$(endpoint "$engine")"
  for _ in {1..20}; do
    if curl --fail --silent --show-error "${lab_endpoint}/health" >/dev/null 2>&1; then
      printf 'Contenedor: %s\n' "$container"
      printf 'Endpoint: %s\n' "$lab_endpoint"
      return
    fi
    sleep 0.25
  done

  "$engine" logs "$container" >&2 || true
  die "El servicio no alcanzó el estado inicial esperado."
}

status() {
  local engine="$1"
  local container=""
  container="$(container_name)"

  if ! container_exists "$engine"; then
    printf 'Intento: %s\n' "$(attempt_id)"
    printf 'Estado: sin contenedor\n'
    return
  fi

  assert_owned_container "$engine"
  printf 'Intento: %s\n' "$(attempt_id)"
  "$engine" inspect \
    --format 'Contenedor: {{.Name}}{{printf "\n"}}Estado: {{.State.Status}}{{printf "\n"}}PID del runtime: {{.State.Pid}}' \
    "$container"
  if [[ "$("$engine" inspect --format '{{.State.Running}}' "$container")" == "true" ]]; then
    printf 'Endpoint: %s\n' "$(endpoint "$engine")"
  fi
}

logs() {
  local engine="$1"
  container_exists "$engine" || die "El intento no está iniciado."
  assert_owned_container "$engine"
  "$engine" logs "$(container_name)"
}

exec_inside() {
  local engine="$1"
  shift
  [[ "$#" -gt 0 ]] || die "Indica el comando que quieres ejecutar dentro del contenedor."
  container_exists "$engine" || die "El intento no está iniciado."
  assert_owned_container "$engine"
  "$engine" exec "$(container_name)" "$@"
}

remove_owned_container() {
  local engine="$1"
  if container_exists "$engine"; then
    assert_owned_container "$engine"
    "$engine" rm --force "$(container_name)" >/dev/null
  fi
}

reset() {
  local engine="$1"
  remove_owned_container "$engine"
  start "$engine"
}

destroy() {
  local engine="$1"
  remove_owned_container "$engine"
  if image_exists "$engine"; then
    assert_owned_image "$engine"
    "$engine" image rm "$(image_name)" >/dev/null
  fi
  printf 'Recursos retirados para el intento %s.\n' "$(attempt_id)"
}

usage() {
  printf '%s\n' \
    "Uso: ./lab <doctor|start|status|endpoint|logs|exec|reset|destroy>" \
    "" \
    "  doctor   valida archivos, usuario y runtime" \
    "  start    construye e inicia el servicio del intento" \
    "  status   muestra el estado y el endpoint si existe" \
    "  endpoint imprime la URL ligada a loopback" \
    "  logs     muestra stdout/stderr del servicio" \
    "  exec     ejecuta un comando dentro del contenedor" \
    "  reset    recrea solo el contenedor etiquetado del intento" \
    "  destroy  retira el contenedor y la imagen etiquetados"
}

main() {
  local command="${1:-}"
  local engine=""
  engine="$(choose_engine)"

  case "$command" in
    doctor)
      doctor "$engine"
      ;;
    start)
      start "$engine"
      ;;
    status)
      doctor "$engine" >/dev/null
      status "$engine"
      ;;
    endpoint)
      doctor "$engine" >/dev/null
      endpoint "$engine"
      ;;
    logs)
      doctor "$engine" >/dev/null
      logs "$engine"
      ;;
    exec)
      shift
      doctor "$engine" >/dev/null
      exec_inside "$engine" "$@"
      ;;
    reset)
      reset "$engine"
      ;;
    destroy)
      doctor "$engine" >/dev/null
      destroy "$engine"
      ;;
    help|-h|--help|"")
      usage
      ;;
    *)
      usage >&2
      die "Comando no reconocido: $command"
      ;;
  esac
}

main "$@"
