#!/usr/bin/env bash

set -u

ENV_FILE="${ENV_FILE:-/etc/hyd-crowdsec/client.env}"
BOUNCER_CONFIG="/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml"

# Modo de arranque. El valor efectivo vive en client.env, así que hay que leerlo
# ANTES de decidir el modo: configure_start_mode() se ejecuta antes que
# configure_firewall_bouncer(), que es donde se sourceaba el fichero hasta ahora.
# Sin este source temprano, START_MODE se congelaba con el valor por defecto y
# `HYD_START_MODE="enforce"` en client.env no tenía ningún efecto (el bootstrap
# tampoco exporta la variable al invocar este script).
START_MODE_OVERRIDE="${HYD_START_MODE:-}"

if [ -f "$ENV_FILE" ]; then
    # shellcheck disable=SC1090
    . "$ENV_FILE"
fi

# Precedencia: variable pasada a mano > client.env > defecto. Desde 1.1.0-6 el
# defecto es enforce: el cliente aplica bloqueos salvo que se pida simulation.
START_MODE="${START_MODE_OVERRIDE:-${HYD_START_MODE:-enforce}}"

apply_simulation_reload() {
    # cscli escribe simulation.yaml, pero el motor en marcha no lo aplica hasta
    # recargar. Sin esto, crowdsec sigue emitiendo decisiones reales aunque la
    # simulación esté "activada", que es justo el fallo que rompe la etapa 1.
    systemctl reload crowdsec 2>/dev/null ||
        systemctl restart crowdsec 2>/dev/null || {
        echo "FAIL: no se pudo recargar crowdsec para aplicar el modo"
        return 1
    }
}

configure_start_mode() {
    case "$START_MODE" in
        simulation)
            cscli simulation enable --global >/dev/null 2>&1 || {
                echo "FAIL: no se pudo activar el modo simulación"
                return 1
            }

            apply_simulation_reload || return 1

            # Nota: crowdsec pudo emitir decisiones reales durante la
            # instalación, antes de esta recarga. No se purgan aquí porque
            # cscli no permite acotar el borrado a esta máquina y hacerlo
            # global tumbaría decisiones de otros clientes. La limpieza del
            # residuo se hace desde el central, acotada por machine_id.
            echo "OK: modo SIMULACIÓN — no se aplicará ningún bloqueo"
            ;;
        enforce)
            cscli simulation disable --global >/dev/null 2>&1 || {
                echo "FAIL: no se pudo desactivar el modo simulación"
                return 1
            }

            apply_simulation_reload || return 1

            echo "OK: modo ENFORCE — los bloqueos se aplicarán"
            ;;
        *)
            echo "FAIL: HYD_START_MODE inválido: $START_MODE"
            return 1
            ;;
    esac
}

configure_firewall_bouncer() {
    command -v crowdsec-firewall-bouncer >/dev/null 2>&1 || {
        echo "FAIL: falta crowdsec-firewall-bouncer-nftables"
        return 1
    }

    test -f "$ENV_FILE" || {
        echo "FAIL: no existe $ENV_FILE"
        return 1
    }

    # shellcheck disable=SC1090
    . "$ENV_FILE"

    test -n "${LAPI_URL:-}" || {
        echo "FAIL: LAPI_URL no definido en $ENV_FILE"
        return 1
    }

    test -n "${BOUNCER_KEY:-}" || {
        echo "FAIL: BOUNCER_KEY no definido en $ENV_FILE"
        return 1
    }

    install -d -m 0750 /etc/crowdsec/bouncers

    TMP_CONFIG="$(mktemp)" || return 1

    # mode: nftables da al bouncer su propia tabla, aislada de las cadenas de
    # CSF. CSF puede recargar sin tocarla y el bouncer nunca toca las de CSF.
    cat > "$TMP_CONFIG" <<EOF
mode: nftables
update_frequency: 10s
log_mode: file
log_dir: /var/log/
log_level: info
api_url: ${LAPI_URL}
api_key: ${BOUNCER_KEY}
deny_action: DROP
nftables:
  ipv4:
    enabled: true
    set-only: false
    table: crowdsec
    chain: crowdsec-chain
  ipv6:
    enabled: false
EOF

    if test -f "$BOUNCER_CONFIG" && cmp -s "$TMP_CONFIG" "$BOUNCER_CONFIG"; then
        rm -f "$TMP_CONFIG"
        echo "OK: configuración del bouncer ya correcta"
    else
        if test -f "$BOUNCER_CONFIG"; then
            cp -a "$BOUNCER_CONFIG" \
                "${BOUNCER_CONFIG}.bak.$(date +%F-%H%M%S)"
        fi

        install -m 0600 "$TMP_CONFIG" "$BOUNCER_CONFIG"
        rm -f "$TMP_CONFIG"
        echo "OK: configuración del bouncer escrita"
    fi

    systemctl enable --now crowdsec-firewall-bouncer.service || {
        echo "FAIL: no se pudo activar crowdsec-firewall-bouncer"
        return 1
    }

    systemctl restart crowdsec-firewall-bouncer.service || {
        echo "FAIL: no se pudo reiniciar crowdsec-firewall-bouncer"
        return 1
    }

    echo "OK: bouncer nftables activo"
}

main() {
    CROWDSEC_CONFIG="/etc/crowdsec/config.yaml"

    echo "===== ACTIVACIÓN HYD CROWDSEC ====="

    command -v systemctl >/dev/null 2>&1 || {
        echo "FAIL: systemctl no está disponible"
        return 1
    }

    command -v crowdsec >/dev/null 2>&1 || {
        echo "FAIL: CrowdSec no está instalado"
        return 1
    }

    test -f "$CROWDSEC_CONFIG" || {
        echo "FAIL: no existe $CROWDSEC_CONFIG"
        return 1
    }

    systemctl daemon-reload || {
        echo "FAIL: systemctl daemon-reload"
        return 1
    }

    echo
    echo "===== ESCENARIOS Y PARSERS ====="

# BEGIN HYD SELF-IP PARSER
echo
echo "===== HYD self IP parser ====="

if test ! -x /usr/local/sbin/hyd-install-self-ip-parser.sh; then
    echo "FAIL: falta /usr/local/sbin/hyd-install-self-ip-parser.sh"
    return 1
fi

if ! /usr/local/sbin/hyd-install-self-ip-parser.sh; then
    echo "FAIL: no se pudo instalar hyd-self-ip parser"
    return 1
fi

echo "OK: hyd-self-ip parser instalado"
# END HYD SELF-IP PARSER

    systemctl start hyd-crowdsec-rules-sync.service || {
        echo "FAIL: sincronización inicial de escenarios y parsers"
        return 1
    }

    systemctl enable --now hyd-crowdsec-rules-sync.timer || {
        echo "FAIL: no se pudo habilitar rules-sync"
        return 1
    }

    echo "OK: sincronización de reglas activa"

    echo
    echo "===== COLECCIONES POR TOPOLOGÍA ====="

    # Este timer nunca se habilitaba: su preset es `disabled` y el activador solo
    # encendia rules-sync y el acquis de DirectAdmin. Resultado: las colecciones
    # se instalaban a mano o no se instalaban, y auditd nunca llegaba al cliente.
    #
    # La ejecucion inicial NO es fatal: depende del hub de CrowdSec (red externa)
    # y un fallo ahi no debe tumbar un enrolamiento con el bouncer ya activo. El
    # timer queda habilitado igualmente y reintentara a diario.
    systemctl start hyd-crowdsec-collections-sync.service ||
        echo "WARN: sincronización inicial de colecciones fallida; reintenta el timer"

    systemctl enable --now hyd-crowdsec-collections-sync.timer || {
        echo "FAIL: no se pudo habilitar collections-sync"
        return 1
    }

    echo "OK: sincronización de colecciones activa"

    echo
    echo "===== ADQUISICIONES DIRECTADMIN ====="

    if test -d /usr/local/directadmin; then
        systemctl start \
            hyd-crowdsec-directadmin-acquis-sync.service || {
            echo "FAIL: generación inicial de acquisitions"
            return 1
        }

        systemctl enable --now \
            hyd-crowdsec-directadmin-acquis-sync.timer || {
            echo "FAIL: no se pudo habilitar acquisitions-sync"
            return 1
        }

        echo "OK: sincronización de acquisitions activa"
    else
        systemctl disable --now \
            hyd-crowdsec-directadmin-acquis-sync.timer \
            >/dev/null 2>&1 || true

        echo "INFO: DirectAdmin no detectado"
    fi

    echo
    echo "===== COLECCIONES SEGÚN TOPOLOGÍA ====="

    if test -x /usr/local/sbin/hyd-crowdsec-collections-sync.sh; then
        /usr/local/sbin/hyd-crowdsec-collections-sync.sh || {
            echo "FAIL: no se pudieron instalar las colecciones"
            return 1
        }
    else
        echo "WARN: falta hyd-crowdsec-collections-sync.sh"
    fi

    echo
    echo "===== VALIDACIÓN CROWDSEC ====="

    crowdsec -c "$CROWDSEC_CONFIG" -t || {
        echo "FAIL: configuración CrowdSec inválida"
        return 1
    }

    echo "OK: configuración CrowdSec válida"

    echo
    echo "===== MODO DE ARRANQUE ====="

    configure_start_mode || return 1

    echo
    echo "===== BOUNCER NFTABLES ====="

    configure_firewall_bouncer || return 1

    echo
    echo "===== ESTADO FINAL ====="

    systemctl --no-pager --full status \
        hyd-crowdsec-rules-sync.timer \
        hyd-crowdsec-directadmin-acquis-sync.timer \
        crowdsec-firewall-bouncer.service \
        2>/dev/null |
    grep -E \
        '^[●○ ]|Loaded:|Active:|Trigger:|Triggers:' ||
    true

    echo
    echo "OK: cliente HYD CrowdSec activado"
}

main "$@"
