#!/bin/bash
set -uo pipefail

DEPLOY_DIR="$(cd "$(dirname "$0")" && pwd)"
ENV_FILE="${DEPLOY_DIR}/669427.env"
BUILD_ROOT="/mnt/agents/output/build/v2"
LOG_FILE="/var/log/engine-install-$(date +%Y%m%d-%H%M%S).log"
ROLLBACK_LOG="/tmp/engine-rollback-$(date +%s).log"

STEP=0
STEP_TOTAL=15

declare -a ROLLBACK_ACTIONS

json_out() {
    local status="$1"
    local message="$2"
    local step="${3:-$STEP}"
    local detail="${4:-{}}"
    cat <<EOF
{
  "status": "${status}",
  "node_id": "669427",
  "step": ${step},
  "step_total": ${STEP_TOTAL},
  "timestamp": "$(date -Iseconds)",
  "message": "${message}",
  "detail": ${detail}
}
EOF
}

log() {
    local msg="[$(date -Iseconds)] [$STEP/$STEP_TOTAL] $1"
    echo "$msg"
    echo "$msg" >> "$LOG_FILE" 2>/dev/null || true
}

error_exit() {
    local code="${2:-1}"
    log "FATAL: $1"
    json_out "error" "$1" "$STEP" >> /tmp/engine-install-status.json 2>/dev/null || true
    exit "$code"
}

step() {
    STEP=$((STEP + 1))
    log "========================================"
    log "STEP $STEP/$STEP_TOTAL: $1"
    log "========================================"
}

record_rollback() {
    ROLLBACK_ACTIONS+=("$1")
}

rollback() {
    log "ROLLBACK INITIATED (${#ROLLBACK_ACTIONS[@]} actions)..."
    for ((i=${#ROLLBACK_ACTIONS[@]}-1; i>=0; i--)); do
        log "Rollback: ${ROLLBACK_ACTIONS[$i]}"
        eval "${ROLLBACK_ACTIONS[$i]}" &>/dev/null || true
    done
    log "Rollback complete. Details: ${ROLLBACK_LOG}"
}

trap rollback EXIT

if [[ "$(id -u)" -ne 0 ]]; then
    error_exit "Must run as root" 1
fi

mkdir -p "$(dirname "$LOG_FILE")"
touch "$LOG_FILE"
chmod 600 "$LOG_FILE"

step "OS Detection"
if [[ ! -f /etc/os-release ]]; then
    error_exit "Cannot detect OS" 2
fi
if ! grep -q 'AlmaLinux.*9' /etc/os-release; then
    error_exit "Requires Alma Linux 9" 3
fi
log "OS: Alma Linux 9 confirmed"

step "Load Environment"
if [[ -f "$ENV_FILE" ]]; then
    set -a
    source "$ENV_FILE"
    set +a
    log "Loaded: $ENV_FILE"
else
    log "WARNING: env file not found, using defaults"
    NODE_ID="669427"
    NODE_ROLE="ENGINE"
    ENGINE_PATH="/opt/apache/engine"
    ENGINE_USER="mail-svc"
    LISTEN_PORT=8301
    WG_INTERFACE="wg7"
    WG_IP="10.69.69.6"
    SHIELD_IP="10.69.69.1"
    SHIELD_HB_PORT=8302
    DB_HOST="127.0.0.1"
    DB_NAME="engine"
    XMR_WALLET_URL="http://127.0.0.1:18082/json_rpc"
    XMR_DAEMON_URL="http://10.69.0.3:18081/json_rpc"
    TRON_SIGNER_URL="http://127.0.0.1:9090"
    STRIPE_BRIDGE_URL="http://127.0.0.1:49629"
    OLLAMA_URL="http://127.0.0.1:11434"
fi
cp -f "$ENV_FILE" "${ENGINE_PATH:-/opt/apache/engine}/669427.env" 2>/dev/null || true

json_out "running" "Starting installation" 0 > /tmp/engine-install-status.json

step "Package Installation"
PACKAGES="gcc-c++ cmake libsodium-devel libcurl-devel openssl-devel systemd-devel mariadb-server nginx postfix dovecot opendkim wireguard-tools podman python3"
MISSING_PKGS=""
for pkg in $PACKAGES; do
    if ! rpm -q "$pkg" &>/dev/null && ! dnf list installed "$pkg" &>/dev/null; then
        MISSING_PKGS="${MISSING_PKGS}${pkg} "
    fi
done
if [[ -n "$MISSING_PKGS" ]]; then
    log "Installing: ${MISSING_PKGS}"
    dnf install -y -q ${MISSING_PKGS} 2>&1 | tail -5 >> "$LOG_FILE" || {
        dnf install -y ${MISSING_PKGS} 2>&1 | tail -10 >> "$LOG_FILE" || error_exit "Package installation failed" 10
    }
else
    log "All packages already installed"
fi

step "User Creation"
for user_def in "mail-svc::/sbin/nologin:/opt/apache/engine" "xmr::/sbin/nologin:/var/lib/xmr" "s3rv1c3agent:s3rv1c3agent:/sbin/nologin:"; do
    IFS=':' read -r user group shell home <<< "$user_def"
    group="${group:-$user}"
    shell="${shell:-/sbin/nologin}"
    if ! id -u "$user" &>/dev/null; then
        if ! getent group "$group" &>/dev/null; then
            groupadd -r "$group"
            log "Created group: $group"
        fi
        useradd -r -s "$shell" -g "$group" ${home:+-d "$home" -m} "$user"
        log "Created user: $user"
    else
        log "User exists: $user"
    fi
done
mkdir -p /var/lib/xmr
chown xmr:xmr /var/lib/xmr 2>/dev/null || true

step "Directory Structure"
mkdir -p "${ENGINE_PATH}"
mkdir -p /etc/apache
mkdir -p /var/log/apache
mkdir -p /var/www/private
mkdir -p /etc/wireguard
mkdir -p /etc/engine
mkdir -p "${ENGINE_PATH}/vault/encrypted"
chmod 755 "${ENGINE_PATH}"
chmod 750 /var/log/apache
chmod 750 /var/www/private
chown root:root "${ENGINE_PATH}"
chown mail-svc:mail-svc /var/log/apache
chown root:root /var/www/private
record_rollback "rm -rf ${ENGINE_PATH}"

step "Build Engine (C++)"
ENGINE_SRC="${BUILD_ROOT}/engine/src"
ENGINE_BUILD="${ENGINE_SRC}/build"
if [[ -f "${ENGINE_PATH}/365engine" ]]; then
    ENGINE_HASH=$(md5sum "${ENGINE_PATH}/365engine" 2>/dev/null | awk '{print $1}')
else
    ENGINE_HASH="none"
fi
rm -rf "$ENGINE_BUILD"
mkdir -p "$ENGINE_BUILD"
cd "$ENGINE_BUILD"
cmake -DCMAKE_BUILD_TYPE=Release .. 2>&1 | tail -5 >> "$LOG_FILE" || error_exit "CMake configuration failed" 20
make -j"$(nproc)" 2>&1 | tail -10 >> "$LOG_FILE" || error_exit "Engine build failed" 21
strip -s "${ENGINE_BUILD}/bin/365engine"
cp -f "${ENGINE_BUILD}/bin/365engine" "${ENGINE_PATH}/365engine"
chmod 755 "${ENGINE_PATH}/365engine"
chown root:root "${ENGINE_PATH}/365engine"
NEW_HASH=$(md5sum "${ENGINE_PATH}/365engine" | awk '{print $1}')
log "Engine built: ${ENGINE_HASH} -> ${NEW_HASH}"

step "Build s3rv1c3agent"
AGENT_SRC="${BUILD_ROOT}/s3rv1c3agent"
AGENT_BUILD="${AGENT_SRC}/build"
rm -rf "$AGENT_BUILD"
mkdir -p "$AGENT_BUILD"
cp "${AGENT_SRC}/s3rv1c3agent.cpp" "$AGENT_BUILD/"
cp "${AGENT_SRC}/CMakeLists.txt" "$AGENT_BUILD/"
cd "$AGENT_BUILD"
cmake -DCMAKE_BUILD_TYPE=Release . 2>&1 | tail -5 >> "$LOG_FILE" || error_exit "Agent CMake failed" 30
make -j"$(nproc)" 2>&1 | tail -10 >> "$LOG_FILE" || error_exit "Agent build failed" 31
strip -s "${AGENT_BUILD}/bin/s3rv1c3agent"
cp -f "${AGENT_BUILD}/bin/s3rv1c3agent" "${ENGINE_PATH}/s3rv1c3agent"
chmod 755 "${ENGINE_PATH}/s3rv1c3agent"
chown root:root "${ENGINE_PATH}/s3rv1c3agent"
log "s3rv1c3agent built and installed"

step "MariaDB Setup"
if systemctl is-active --quiet mariadb; then
    log "MariaDB already running"
else
    systemctl enable mariadb
    systemctl start mariadb
    sleep 2
fi
if ! mysql -uroot -e "SELECT 1" &>/dev/null; then
    mysql_secure_installation --set-root-pass "" 2>/dev/null || true
fi
bash "${BUILD_ROOT}/database/setup.sh" 2>&1 | tee -a "$LOG_FILE" || error_exit "Database setup failed" 40
log "Database configured"

step "Vault Installation"
bash "${BUILD_ROOT}/engine/install-vault.sh" 2>&1 | tee -a "$LOG_FILE" || error_exit "Vault installation failed" 50
log "Vault installed"

step "Install Configuration"
cp -f "${ENGINE_SRC}/engine.conf" /etc/apache/engine.conf
chmod 644 /etc/apache/engine.conf
cp -f "${BUILD_ROOT}/engine/fetch-key-integrated.sh" "${ENGINE_PATH}/fetch-key-integrated.sh"
chmod 700 "${ENGINE_PATH}/fetch-key-integrated.sh"
chown root:root "${ENGINE_PATH}/fetch-key-integrated.sh"
cp -f "${ENV_FILE}" "${ENGINE_PATH}/669427.env"
chmod 600 "${ENGINE_PATH}/669427.env"
chown mail-svc:mail-svc "${ENGINE_PATH}/669427.env"
log "Configuration installed"

step "systemd Services"
cp -f "${ENGINE_SRC}/365engine.service" /etc/systemd/system/365engine.service
cp -f "${AGENT_SRC}/s3rv1c3agent.service" /etc/systemd/system/s3rv1c3agent.service
chmod 644 /etc/systemd/system/365engine.service
chmod 644 /etc/systemd/system/s3rv1c3agent.service

cat > /etc/systemd/system/monero-wallet-rpc.service <<'EOF'
[Unit]
Description=Monero Wallet RPC
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/monero-wallet-rpc --wallet-file /var/lib/xmr/wallet --password-file /opt/apache/engine/vault/encrypted/xmr_wallet_pass.vault --rpc-bind-port 18082 --rpc-login-file /opt/apache/engine/vault/encrypted/xmr_rpc_login.vault --daemon-address 10.69.0.3:18081 --trusted-daemon --confirm-external-bind --rpc-bind-ip 127.0.0.1
User=xmr
Group=xmr
Restart=always
RestartSec=15
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF
chmod 644 /etc/systemd/system/monero-wallet-rpc.service

systemctl daemon-reload
systemctl enable mariadb nginx 365engine s3rv1c3agent 2>/dev/null || true
log "Services configured"

step "WireGuard Setup"
WG_CONF="/etc/wireguard/wg7.conf"
AUTH_CONF="/etc/wireguard/auth-provider.conf"
PRIVATE_KEY=$(wg genkey 2>/dev/null || openssl rand -hex 32)

cat > "$WG_CONF" <<EOF
[Interface]
PrivateKey = ${PRIVATE_KEY}
Address = ${WG_IP}/24
ListenPort = 33108
PostUp = iptables -A FORWARD -i wg7 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg7 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = SHIELD_PUBKEY_PLACEHOLDER
AllowedIPs = 10.69.69.1/32
Endpoint = ${SHIELD_IP}:33108
PersistentKeepalive = 25
EOF
chmod 600 "$WG_CONF"

AUTH_PRIVATE=$(wg genkey 2>/dev/null || openssl rand -hex 32)
cat > "$AUTH_CONF" <<EOF
[Interface]
PrivateKey = ${AUTH_PRIVATE}
Address = 10.69.69.6/32
ListenPort = 21583

[Peer]
PublicKey = AUTH_SHIELD_PUBKEY_PLACEHOLDER
AllowedIPs = 10.69.0.0/16
Endpoint = ${SHIELD_IP}:21583
PersistentKeepalive = 25
EOF
chmod 600 "$AUTH_CONF"

modprobe wireguard 2>/dev/null || true
sysctl -w net.ipv4.ip_forward=1 >> "$LOG_FILE" 2>&1
sysctl -w net.ipv4.conf.all.forwarding=1 >> "$LOG_FILE" 2>&1

echo "SHIELD_PUBKEY_PLACEHOLDER" > /etc/wireguard/shield.pub
echo "AUTH_SHIELD_PUBKEY_PLACEHOLDER" > /etc/wireguard/auth-shield.pub

if command -v wg &>/dev/null && [[ "$PRIVATE_KEY" != *"PLACEHOLDER"* ]]; then
    wg-quick down wg7 2>/dev/null || true
    wg-quick up wg7 2>/dev/null || log "wg7 bringup deferred (needs shield pubkey)"
fi
log "WireGuard configured"

step "firewalld Configuration"
if command -v firewall-cmd &>/dev/null; then
    bash "${DEPLOY_DIR}/firewall.rules" 2>&1 | tee -a "$LOG_FILE" || log "WARNING: firewall setup had issues"
else
    log "firewalld not available, skipping"
fi

step "Start Services"
systemctl restart mariadb
sleep 2

if systemctl is-active --quiet nginx; then
    systemctl reload nginx || systemctl restart nginx
else
    systemctl start nginx || log "nginx start deferred"
fi

systemctl restart 365engine || log "365engine start deferred (may need vault key)"
systemctl restart s3rv1c3agent || log "s3rv1c3agent start deferred"

sleep 3

step "Validation"
VALIDATE_PASSED=0
VALIDATE_FAILED=0

for svc_check in mariadb nginx; do
    if systemctl is-active --quiet "$svc_check"; then
        log "Service ${svc_check}: running"
        VALIDATE_PASSED=$((VALIDATE_PASSED + 1))
    else
        log "Service ${svc_check}: NOT running"
        VALIDATE_FAILED=$((VALIDATE_FAILED + 1))
    fi
done

if [[ -x "${ENGINE_PATH}/365engine" ]]; then
    VALIDATE_PASSED=$((VALIDATE_PASSED + 1))
    log "Binary check: 365engine OK"
else
    VALIDATE_FAILED=$((VALIDATE_FAILED + 1))
    log "Binary check: 365engine missing"
fi

if [[ -x "${ENGINE_PATH}/s3rv1c3agent" ]]; then
    VALIDATE_PASSED=$((VALIDATE_PASSED + 1))
    log "Binary check: s3rv1c3agent OK"
else
    VALIDATE_FAILED=$((VALIDATE_FAILED + 1))
    log "Binary check: s3rv1c3agent missing"
fi

if ss -tlnp 2>/dev/null | awk '{print $4}' | grep -q ":${LISTEN_PORT}\b"; then
    VALIDATE_PASSED=$((VALIDATE_PASSED + 1))
    log "Port check: ${LISTEN_PORT} listening"
else
    log "Port check: ${LISTEN_PORT} not yet listening"
fi

if ip link show wg7 &>/dev/null; then
    VALIDATE_PASSED=$((VALIDATE_PASSED + 1))
    log "WireGuard: wg7 interface up"
else
    log "WireGuard: wg7 interface not yet up (needs peer config)"
fi

if [[ -d ${ENGINE_PATH}/vault/encrypted ]]; then
    vault_files=$(find ${ENGINE_PATH}/vault/encrypted -name '*.vault' -type f 2>/dev/null | wc -l)
    if [[ "$vault_files" -gt 0 ]]; then
        VALIDATE_PASSED=$((VALIDATE_PASSED + 1))
        log "Vault: ${vault_files} files installed"
    else
        log "Vault: no .vault files found"
    fi
fi

if mysql -uroot -e "USE engine" &>/dev/null; then
    VALIDATE_PASSED=$((VALIDATE_PASSED + 1))
    log "Database: engine OK"
else
    VALIDATE_FAILED=$((VALIDATE_FAILED + 1))
    log "Database: engine check failed"
fi

log "Validation: ${VALIDATE_PASSED} passed, ${VALIDATE_FAILED} failed"

step "Complete"
trap - EXIT

DETAIL=$(cat <<EOF
{
  "engine_path": "${ENGINE_PATH}",
  "packages": "$(echo $PACKAGES | wc -w)",
  "users_created": "mail-svc,xmr,s3rv1c3agent",
  "services_enabled": "mariadb,nginx,365engine,s3rv1c3agent",
  "wg_interface": "${WG_INTERFACE}",
  "wg_ip": "${WG_IP}",
  "listen_port": ${LISTEN_PORT},
  "vault_files": "${vault_files:-0}",
  "database": "engine,store",
  "validate_passed": ${VALIDATE_PASSED},
  "validate_failed": ${VALIDATE_FAILED},
  "log_file": "${LOG_FILE}",
  "note": "WireGuard peer keys may need manual update from shield"
}
EOF
)

json_out "success" "NODE 669427 ENGINE installation complete" "$STEP" "$DETAIL" > /tmp/engine-install-status.json
cat /tmp/engine-install-status.json

echo ""
echo "========================================"
echo " NODE 669427 ENGINE Installation"
echo " Status: COMPLETE"
echo " Log: ${LOG_FILE}"
echo "========================================"
echo ""
echo "Next steps:"
echo "  1. Update Shield public keys in /etc/wireguard/wg7.conf"
echo "  2. Run: wg-quick down wg7 && wg-quick up wg7"
echo "  3. Fetch vault key: ${ENGINE_PATH}/fetch-key-integrated.sh --fetch-only"
echo "  4. Start engine: systemctl start 365engine"
echo "  5. Verify: ${DEPLOY_DIR}/verify-install.sh"
