#!/bin/bash
# VAC - Vitalinux Autoregistration Client

set -euo pipefail

CONF_FILE="/etc/vac/vac.conf"
CONF_DIR="/etc/vac/vac.conf.d"
ID_FILE="/etc/vac/vac-id"
STATE_DIR="/var/lib/vac"
VERSION_FILE="${STATE_DIR}/version"
TMP_CONFIG="${STATE_DIR}/computers.json.tmp"

VAS_HOST="${VAS_HOST:-}"
RETRY_SECONDS=60
CHECK_SECONDS=300
VEYON_CONFIG="/etc/veyon/computers.json"
CONFIG_ENDPOINT="/config"
VEYON_ROOM="Autoregistrados"

if [[ -f "$CONF_FILE" ]]; then
    # shellcheck disable=SC1090
    source "$CONF_FILE"
fi

if [[ -d "$CONF_DIR" ]]; then
    # Aplica overlays en orden lexical: /etc/vac/vac.conf.d/*.conf
    for cfg in "$CONF_DIR"/*.conf; do
        [[ -f "$cfg" ]] || continue
        # shellcheck disable=SC1090
        source "$cfg"
    done
fi

mkdir -p "$STATE_DIR"

if [[ ! -f "$ID_FILE" ]]; then
    uuidgen > "$ID_FILE"
    chmod 600 "$ID_FILE"
fi

if [[ ! -f "$VERSION_FILE" ]]; then
    echo "0" > "$VERSION_FILE"
fi

CLIENT_ID="$(tr -d '[:space:]' < "$ID_FILE")"

# Emite mensajes con prefijo VAC para journald/systemd.
log() {
    echo "[VAC] $*"
}

# Devuelve el hostname preferentemente en formato FQDN.
get_hostname() {
    hostname -f 2>/dev/null || hostname
}

# Devuelve la IP de salida. Si no hay red lista, devuelve cadena vacia.
get_ip() {
    ip route get 1.1.1.1 2>/dev/null | awk '/src/ {for (i=1; i<=NF; i++) if ($i=="src") {print $(i+1); exit}}' || true
}

# Devuelve la primera MAC ethernet detectada. Si falla, devuelve vacio.
get_mac() {
    ip link show 2>/dev/null | awk '/link\/ether/ {print $2; exit}' || true
}

# Registra el cliente en VAS usando UUID persistente como identificador.
register_client() {
    local host ip mac payload
    host="$(get_hostname)"
    ip="$(get_ip)"
    mac="$(get_mac)"

    # IP vacía → no registrar
    if [[ -z "$ip" ]]; then
        log "IP vacía. No se registra."
        return 1
    fi

    # MAC vacía → registrar igualmente
    if [[ -z "$mac" ]]; then
        log "MAC vacía. Registrando sin MAC."
    fi

    payload="$(jq -n \
      --arg id "$CLIENT_ID" \
      --arg hostname "$host" \
      --arg ip "$ip" \
      --arg mac "$mac" \
      '{id:$id, hostname:$hostname, ip:$ip, mac:$mac}')"

    curl -fsS -X POST "${VAS_HOST%/}/register" \
      -H "Content-Type: application/json" \
      -d "$payload" >/dev/null
}

# Consulta la version de configuracion publicada por VAS.
get_remote_version() {
    curl -fsS "${VAS_HOST%/}/version" | jq -r '.version'
}

# Descarga el JSON remoto y lo instala localmente, importandolo en Veyon si existe.
download_and_apply_config() {
    curl -fsS "${VAS_HOST%/}${CONFIG_ENDPOINT}" -o "$TMP_CONFIG"

    local dest_dir
    dest_dir="$(dirname "$VEYON_CONFIG")"
    mkdir -p "$dest_dir"

    install -m 0644 "$TMP_CONFIG" "$VEYON_CONFIG"

    if ! command -v veyon-cli >/dev/null 2>&1; then
        log "veyon-cli no encontrado. Configuración escrita en '$VEYON_CONFIG', pero no importada."
        return 0
    fi

    # Veyon CLI de Vitalinux no importa JSON directamente con networkobjects import.
    # Convertimos computers.json a CSV y usamos un formato completo con
    # %type%, %name%, %host%, %mac% y %location%.
    local csv_file safe_location
    csv_file="${STATE_DIR}/computers.csv"
    safe_location="${VEYON_ROOM//;/}"

    if ! jq -r --arg location "$safe_location" '.computers[]? | "computer;\((.hostname // "" | gsub(";"; "")));\((.ip // "" | gsub(";"; "")));\((.mac // "" | gsub(";"; "")));\($location)"' "$TMP_CONFIG" > "$csv_file"; then
        log "Error al convertir configuración JSON a CSV para Veyon."
        return 1
    fi

    # Eliminamos solo la location gestionada por VAC para no afectar otras.
    if ! veyon-cli networkobjects remove "$safe_location" >/dev/null 2>&1; then
        log "No se pudo limpiar la location '$safe_location' en Veyon. Continuando con importación."
    fi

    if ! veyon-cli networkobjects import "$csv_file" format "%type%;%name%;%host%;%mac%;%location%"; then
        log "Error al importar configuración en Veyon con formato CSV."
        return 1
    fi

    return 0
}

# Bucle de servicio: registrar, comprobar version y aplicar cambios cuando corresponda.
while true; do
    if [[ -z "$VAS_HOST" ]]; then
        log "VAS_HOST no definido. Esperando ${RETRY_SECONDS}s."
        sleep "$RETRY_SECONDS"
        continue
    fi

    if ! register_client; then
        log "No se pudo registrar en VAS. Reintentando en ${RETRY_SECONDS}s."
        sleep "$RETRY_SECONDS"
        continue
    fi

    local_version="$(tr -d '[:space:]' < "$VERSION_FILE")"

    # Obtener versión remota con log si falla
    remote_version_raw="$(get_remote_version || echo "")"
    if [[ -z "$remote_version_raw" ]]; then
        log "No se pudo obtener la versión remota. Usando versión local."
        remote_version="$local_version"
    elif [[ "$remote_version_raw" =~ ^[0-9]+$ ]]; then
        remote_version="$remote_version_raw"
    else
        log "Versión remota inválida: '$remote_version_raw'. Usando versión local."
        remote_version="$local_version"
    fi

    if [[ "$remote_version" != "$local_version" ]]; then
        if download_and_apply_config; then
            echo "$remote_version" > "$VERSION_FILE"
            log "Configuración aplicada correctamente. Versión ${remote_version}."
        else
            log "Error al descargar/aplicar configuración. Se mantiene versión local ${local_version}."
        fi
    fi

    sleep "$CHECK_SECONDS"
done

