#!/usr/bin/env bash
# Tier-3 + Tier-4 deploy orchestrator. Idempotent. ZERO operator
# interaction — including no API key, no signup, no manual upload.
#
# Steps (each idempotent on its own):
#   1. install-msfrpcd.sh    — auto-install metasploit-framework via
#                              Rapid7 omnibus + drop systemd unit
#   2. fetch-metasploitable2.sh — pull the disk image from the
#                              SourceForge public mirror (TOFU)
#   3. setup_bridge.sh       — bring up br-malware host-only bridge
#                              for callback-payload modules
#   4. Tier-3 verify         — fire vsftpd_234_backdoor against the
#                              freshly-fetched VM, confirm session
#                              lands and an episode is recorded
#   5. Tier-4 deploy         — clone theZoo (public security-research
#                              repo, no auth), extract one real
#                              binary per manifest family, stage at
#                              samples/store/<sha256>, rewrite
#                              manifest.toml in place. MANDATORY:
#                              the deploy fails if zero samples land.
#
# Inputs (env, all optional):
#   SKIP_VERIFY     — set to skip the live Tier-3 fire test
#   SKIP_BRIDGE     — set to skip bridge setup (limits to non-callback modules)
#   SKIP_TIER4      — set to skip Tier-4 deploy entirely (DEPRECATED;
#                     leaves you with mimic-only data, defeats the project)
#
# Run as root from anywhere on the lab host. Sub-scripts handle their
# own root checks.

set -euo pipefail

REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
INSTALL_ROOT="${INSTALL_ROOT:-/opt/cis490}"
DATA_ROOT="${DATA_ROOT:-/var/lib/cis490}"
ETC_ROOT="${ETC_ROOT:-/etc/cis490}"

log() { printf '[install-tier-3-4] %s\n' "$*" >&2; }
die() { log "FATAL: $*"; exit 1; }

[[ $EUID -eq 0 ]] || die "must run as root"

# Resolve script paths — prefer $INSTALL_ROOT (production) over
# $REPO_ROOT (dev clone) so a re-run under systemd uses the same
# scripts the orchestrator does.
script_path() {
    local name="$1"
    if [[ -x "$INSTALL_ROOT/scripts/$name" ]]; then echo "$INSTALL_ROOT/scripts/$name"; return
    elif [[ -x "$REPO_ROOT/scripts/$name" ]]; then echo "$REPO_ROOT/scripts/$name"; return
    elif [[ -x "$INSTALL_ROOT/vm/$name" ]]; then echo "$INSTALL_ROOT/vm/$name"; return
    elif [[ -x "$REPO_ROOT/vm/$name" ]]; then echo "$REPO_ROOT/vm/$name"; return
    else die "$name not found in $INSTALL_ROOT or $REPO_ROOT"
    fi
}

# --- 1. msfrpcd --------------------------------------------------------
log "[1/5] install metasploit-framework + msfrpcd unit"
"$(script_path install-msfrpcd.sh)"

if ! systemctl is-active --quiet cis490-msfrpcd; then
    log "starting cis490-msfrpcd"
    systemctl enable --now cis490-msfrpcd
fi
sleep 3
if ! ss -ltn 2>/dev/null | grep -q ':55553'; then
    log "cis490-msfrpcd not listening on 127.0.0.1:55553 yet — waiting up to 30s"
    for _ in $(seq 1 30); do
        ss -ltn 2>/dev/null | grep -q ':55553' && break
        sleep 1
    done
fi
ss -ltn 2>/dev/null | grep -q ':55553' || \
    die "msfrpcd never bound to :55553 — check 'journalctl -u cis490-msfrpcd'"
log "msfrpcd ✓"

# --- 2. metasploitable2 image ------------------------------------------
log "[2/5] fetch Metasploitable2 disk image"
OUT_DIR="$DATA_ROOT/vm/images"
install -d -m 0755 -o cis490 -g cis490 "$OUT_DIR"
OUT_DIR="$OUT_DIR" "$(script_path fetch-metasploitable2.sh)"
chown cis490:cis490 "$OUT_DIR/metasploitable2.qcow2" 2>/dev/null || true
log "metasploitable2.qcow2 ✓"

# --- 3. bridge ---------------------------------------------------------
if [[ -z "${SKIP_BRIDGE:-}" ]]; then
    log "[3/5] bring up br-malware host-only bridge"
    "$(script_path setup_bridge.sh)" || log "bridge setup failed (non-fatal); only non-callback modules will fire"
    log "br-malware ✓"
else
    log "[3/5] SKIP_BRIDGE set — limiting to non-callback modules"
fi

# --- 4. Tier-3 verify --------------------------------------------------
# Uses distccd_command_exec (SLIRP-safe bind_perl, no bridge required).
# vsftpd_234_backdoor hardcodes port 6200 which collides across SLIRP
# slots and requires the host-only bridge — not usable as a SLIRP verify.
# distccd: service on guest:3632 → host:5632; bind shell on guest:4444.
if [[ -z "${SKIP_VERIFY:-}" ]]; then
    log "[4/5] verify Tier-3 fire (distccd_command_exec)"
    set -a
    # shellcheck disable=SC1091
    . "$ETC_ROOT/msfrpc.env"
    set +a
    PY="$INSTALL_ROOT/.venv/bin/python"
    [[ -x "$PY" ]] || PY="$(command -v python3)"
    if ! TARGET_PORTS="5632:3632,4444:4444" PORT_BASE=5632 \
            sudo -E -u cis490 "$PY" "$INSTALL_ROOT/tools/run_tier3_demo.py" \
            --module distccd_command_exec \
            --target-port 5632 \
            --data-root "$DATA_ROOT/data" \
            --target-boot-timeout 240 \
            > /tmp/cis490-tier3-verify.log 2>&1; then
        log "verify run failed — log at /tmp/cis490-tier3-verify.log; dumping last 30 lines:"
        tail -30 /tmp/cis490-tier3-verify.log >&2 || true
        die "Tier-3 fire failed"
    fi
    if grep -q '^episode_id = ' /tmp/cis490-tier3-verify.log; then
        log "Tier-3 verified ✓ ($(grep '^episode_id = ' /tmp/cis490-tier3-verify.log))"
    else
        log "verify run finished but no episode_id seen — log at /tmp/cis490-tier3-verify.log"
    fi
else
    log "[4/5] SKIP_VERIFY set"
fi

# --- 5. Tier-4 deploy (MANDATORY, no auth required) --------------------
if [[ -n "${SKIP_TIER4:-}" ]]; then
    log "[5/5] SKIP_TIER4 set — leaving this host on Tier 2/3 mimic-only."
    log "      This is NOT the recommended configuration; the project's"
    log "      training target is real-binary episodes."
else
    log "[5/5] Tier-4 deploy (real malware fetch from theZoo — mandatory)"

    command -v git >/dev/null || die "git not installed; need it to clone theZoo"

    PY="$INSTALL_ROOT/.venv/bin/python"
    [[ -x "$PY" ]] || PY="$(command -v python3)"

    # theZoo clone lives on shared persistent storage so re-runs don't
    # re-download. cis490 user owns it for periodic git pull.
    THEZOO_DIR="${THEZOO_DIR:-/var/lib/cis490/theZoo}"
    install -d -o cis490 -g cis490 -m 0755 "$(dirname "$THEZOO_DIR")"

    if ! sudo -E -u cis490 "$PY" \
            "$INSTALL_ROOT/tools/auto_fetch_samples.py" \
            --thezoo-clone-dir "$THEZOO_DIR" \
            > /tmp/cis490-tier4-deploy.log 2>&1; then
        log "Tier-4 fetch failed — last 30 lines of /tmp/cis490-tier4-deploy.log:"
        tail -30 /tmp/cis490-tier4-deploy.log >&2 || true
        die "Tier-4 deploy failed; without real binaries this host produces only mimics"
    fi
    REAL_COUNT="$(ls "$INSTALL_ROOT/samples/store/" 2>/dev/null | wc -l)"
    if [[ "$REAL_COUNT" -lt 1 ]]; then
        log "auto_fetch_samples.py exited 0 but samples/store/ is empty — see /tmp/cis490-tier4-deploy.log"
        tail -30 /tmp/cis490-tier4-deploy.log >&2 || true
        die "Tier-4 deploy failed: no real binaries staged"
    fi
    log "Tier-4 ✓ ($REAL_COUNT real binaries staged in $INSTALL_ROOT/samples/store/)"
fi

# Restart the orchestrator now so the next wave actually runs Tier-3
# against the freshly-staged msfrpcd + samples. Skipped only if the
# unit isn't enabled yet (first install hasn't run `systemctl enable`).
if systemctl is-enabled --quiet cis490-orchestrator 2>/dev/null; then
    log "restarting cis490-orchestrator to pick up new modules + samples"
    systemctl restart cis490-orchestrator || \
        log "WARN: orchestrator restart failed — check 'journalctl -u cis490-orchestrator'"
fi

log ""
log "================================================================="
log "  Tier-3 deploy complete on $(hostname)"
log "================================================================="
log "  - metasploit-framework + cis490-msfrpcd.service active"
log "  - $OUT_DIR/metasploitable2.qcow2 staged"
log "  - bridge: $(ip link show br-malware >/dev/null 2>&1 && echo up || echo skipped)"
log "  - Tier-4: $(ls "$INSTALL_ROOT/samples/store/" 2>/dev/null | wc -l) real binaries staged"
log "================================================================="
