#!/bin/bash
set -uo pipefail

NODE_ID="669427"
NODE_ROLE="ENGINE"
ENGINE_PATH="/opt/apache/engine"
ENV_FILE="${ENGINE_PATH}/669427.env"
REPORT_FILE="/tmp/verify-${NODE_ID}-$(date +%s).json"

PASS=0
FAIL=0
WARN=0
TOTAL=0

RESULTS=()

log_pass() {
    PASS=$((PASS + 1))
    RESULTS+=("{\"test\":\"$1\",\"status\":\"PASS\",\"detail\":\"$2\"}")
    echo "[PASS] $1: $2"
}

log_fail() {
    FAIL=$((FAIL + 1))
    RESULTS+=("{\"test\":\"$1\",\"status\":\"FAIL\",\"detail\":\"$2\"}")
    echo "[FAIL] $1: $2" >&2
}

log_warn() {
    WARN=$((WARN + 1))
    RESULTS+=("{\"test\":\"$1\",\"status\":\"WARN\",\"detail\":\"$2\"}")
    echo "[WARN] $1: $2"
}

run_test() {
    TOTAL=$((TOTAL + 1))
    local name="$1"
    local cmd="$2"
    if eval "$cmd" &>/dev/null; then
        log_pass "$name" "OK"
        return 0
    else
        log_fail "$name" "Check failed"
        return 1
    fi
}

echo "========================================"
echo " NODE ${NODE_ID} (${NODE_ROLE}) Verification"
echo " $(date -Iseconds)"
echo "========================================"
echo ""

if [[ -f "$ENV_FILE" ]]; then
    set -a
    source "$ENV_FILE"
    set +a
    log_pass "ENV001" "Environment loaded from ${ENV_FILE}"
else
    log_warn "ENV001" "Environment file not found, using defaults"
    WG_IP="10.69.69.6"
    SHIELD_IP="10.69.69.1"
    LISTEN_PORT=8301
fi

ENGINE_IP="${WG_IP:-10.69.69.6}"

run_test "OS001" "grep -q 'AlmaLinux.*9' /etc/os-release"

for pkg in gcc-c++ cmake libsodium-devel libcurl-devel openssl-devel systemd-devel mariadb-server nginx postfix dovecot opendkim wireguard-tools podman python3; do
    if rpm -q "$pkg" &>/dev/null || dnf list installed "$pkg" &>/dev/null; then
        log_pass "PKG_${pkg}" "Installed"
    else
        log_fail "PKG_${pkg}" "Not installed"
    fi
done

for user in mail-svc xmr s3rv1c3agent; do
    run_test "USR_${user}" "id -u ${user}"
done

for svc in 365engine s3rv1c3agent mariadb nginx postfix dovecot opendkim; do
    if systemctl list-unit-files "${svc}.service" &>/dev/null; then
        log_pass "SVC_EXIST_${svc}" "Service file exists"
    else
        log_fail "SVC_EXIST_${svc}" "Service file missing"
    fi
done

for svc in 365engine s3rv1c3agent mariadb nginx postfix dovecot opendkim; do
    if systemctl is-active --quiet "${svc}.service" 2>/dev/null; then
        log_pass "SVC_RUN_${svc}" "Active"
    else
        if [[ "$svc" == "opendkim" ]] || [[ "$svc" == "postfix" ]] || [[ "$svc" == "dovecot" ]]; then
            log_warn "SVC_RUN_${svc}" "Not active (may require manual start)"
        else
            log_fail "SVC_RUN_${svc}" "Not active"
        fi
    fi
done

run_test "BIN_ENGINE" "test -x ${ENGINE_PATH}/365engine"
run_test "BIN_AGENT" "test -x ${ENGINE_PATH}/s3rv1c3agent"

if [[ -f /etc/apache/engine.conf ]]; then
    log_pass "CONF_ENGINE" "engine.conf exists"
else
    log_fail "CONF_ENGINE" "engine.conf missing"
fi

if [[ -d ${ENGINE_PATH}/vault/encrypted ]]; then
    perms=$(stat -c '%a' ${ENGINE_PATH}/vault/encrypted)
    owner=$(stat -c '%U:%G' ${ENGINE_PATH}/vault/encrypted)
    if [[ "$perms" == "700" ]] && [[ "$owner" == "mail-svc:mail-svc" ]]; then
        log_pass "VAULT_DIR" "Vault directory permissions correct (${perms} ${owner})"
    else
        log_warn "VAULT_DIR" "Vault permissions ${perms} ${owner}, expected 700 mail-svc:mail-svc"
    fi
else
    log_fail "VAULT_DIR" "Vault directory missing"
fi

if [[ -f ${ENGINE_PATH}/vault_manifest.json ]]; then
    log_pass "VAULT_MANIFEST" "Manifest exists"
    vault_count=$(jq '.files | length' ${ENGINE_PATH}/vault_manifest.json 2>/dev/null || echo 0)
    log_pass "VAULT_COUNT" "${vault_count} vault files registered"
else
    log_fail "VAULT_MANIFEST" "Manifest missing"
fi

missing_vault=0
if [[ -f ${ENGINE_PATH}/vault_manifest.json ]]; then
    while IFS= read -r vfile; do
        if [[ -f "${ENGINE_PATH}/vault/encrypted/${vfile}" ]]; then
            if [[ "$(stat -c '%a' ${ENGINE_PATH}/vault/encrypted/${vfile})" == "600" ]]; then
                log_pass "VAULT_${vfile}" "Present (600)"
            else
                log_warn "VAULT_${vfile}" "Wrong permissions"
            fi
        else
            log_fail "VAULT_${vfile}" "Missing"
            missing_vault=$((missing_vault + 1))
        fi
    done < <(jq -r '.files[].file' ${ENGINE_PATH}/vault_manifest.json 2>/dev/null)
fi

run_test "DB_RUN" "systemctl is-active --quiet mariadb"

if mysql -uroot -e "SELECT 1" &>/dev/null; then
    log_pass "DB_CONN" "Root connection OK"

    if mysql -uroot -e "USE engine" &>/dev/null; then
        log_pass "DB_ENGINE" "engine database exists"
        eng_tables=$(mysql -uroot -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='engine'" 2>/dev/null | tail -1)
        if [[ "${eng_tables:-0}" -ge 20 ]]; then
            log_pass "DB_ENG_TABLES" "${eng_tables} tables"
        else
            log_warn "DB_ENG_TABLES" "Only ${eng_tables} tables"
        fi
    else
        log_fail "DB_ENGINE" "engine database missing"
    fi

    if mysql -uroot -e "USE store" &>/dev/null; then
        log_pass "DB_STORE" "store database exists"
        store_tables=$(mysql -uroot -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='store'" 2>/dev/null | tail -1)
        if [[ "${store_tables:-0}" -ge 50 ]]; then
            log_pass "DB_STORE_TABLES" "${store_tables} tables"
        else
            log_warn "DB_STORE_TABLES" "Only ${store_tables} tables"
        fi
    else
        log_warn "DB_STORE" "store database missing"
    fi

    for dbuser in engine_read engine_write engine_admin; do
        if mysql -uroot -e "SELECT 1 FROM mysql.user WHERE user='${dbuser}'" 2>/dev/null | grep -q 1; then
            log_pass "DB_USER_${dbuser}" "Exists"
        else
            log_fail "DB_USER_${dbuser}" "Missing"
        fi
    done
else
    log_fail "DB_CONN" "Cannot connect to MariaDB"
fi

for port in 8301 8443 3306; do
    if ss -tlnp | awk '{print $4}' | grep -q ":${port}\b"; then
        log_pass "PORT_${port}" "Listening"
    else
        if [[ "$port" == "8443" ]]; then
            log_warn "PORT_${port}" "Not listening (nginx SSL may be optional)"
        else
            log_fail "PORT_${port}" "Not listening"
        fi
    fi
done

if ss -tlnp | awk '{print $4}' | grep -q ':18082\b'; then
    log_pass "PORT_18082" "monero-wallet-rpc listening"
else
    log_warn "PORT_18082" "monero-wallet-rpc not listening (may need wallet load)"
fi

if ip link show wg7 &>/dev/null; then
    log_pass "WG7_IFACE" "Interface exists"

    wg_handshake=$(wg show wg7 latest-handshakes 2>/dev/null | awk '{print $2}' | head -1)
    if [[ -n "$wg_handshake" ]]; then
        now=$(date +%s)
        age=$((now - wg_handshake))
        if [[ $age -lt 300 ]]; then
            log_pass "WG7_HS" "Handshake ${age}s ago"
        else
            log_warn "WG7_HS" "Handshake stale (${age}s)"
        fi
    else
        log_warn "WG7_HS" "No handshake data"
    fi

    wg_peers=$(wg show wg7 peers | wc -l)
    log_pass "WG7_PEERS" "${wg_peers} peer(s)"
else
    log_fail "WG7_IFACE" "wg7 interface missing"
fi

if ip link show auth-provider &>/dev/null; then
    log_pass "WG_AUTH_IFACE" "auth-provider interface exists"
else
    log_warn "WG_AUTH_IFACE" "auth-provider interface missing"
fi

HEALTH_STATUS="unknown"
if command -v curl &>/dev/null; then
    HEALTH_RESP=$(curl -s --max-time 8 "http://${ENGINE_IP}:${LISTEN_PORT:-8301}/health" 2>/dev/null || echo "")
    if [[ -n "$HEALTH_RESP" ]]; then
        log_pass "HTTP_HEALTH" "Engine responded"
        if echo "$HEALTH_RESP" | grep -qi '"status".*"ok"' || echo "$HEALTH_RESP" | grep -qi '"ok"'; then
            log_pass "HTTP_HEALTH_OK" "Health status OK"
            HEALTH_STATUS="ok"
        else
            log_warn "HTTP_HEALTH_OK" "Health unclear: ${HEALTH_RESP:0:80}"
        fi
    else
        log_fail "HTTP_HEALTH" "No response from engine"
    fi

    if [[ -f /var/www/private/bridge_hmac.key ]]; then
        HMAC_KEY=$(cat /var/www/private/bridge_hmac.key)
        TIMESTAMP=$(date +%s)
        NONCE=$(openssl rand -hex 8)
        PAYLOAD="VERIFY|${TIMESTAMP}|${NONCE}"
        HMAC_SIG=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$HMAC_KEY" -binary | base64 -w0)

        HMAC_RESP=$(curl -s --max-time 8 \
            -H "X-Node: ${NODE_ID}" \
            -H "X-Timestamp: ${TIMESTAMP}" \
            -H "X-Nonce: ${NONCE}" \
            -H "X-HMAC: ${HMAC_SIG}" \
            "http://${ENGINE_IP}:${LISTEN_PORT:-8301}/verify" 2>/dev/null || echo "")

        if [[ -n "$HMAC_RESP" ]] && [[ "$HMAC_RESP" != *"DENIED"* ]] && [[ "$HMAC_RESP" != *"denied"* ]]; then
            log_pass "HMAC_VERIFY" "HMAC accepted by engine"
        else
            log_warn "HMAC_VERIFY" "HMAC verification unclear: ${HMAC_RESP:0:80}"
        fi
    else
        log_warn "HMAC_VERIFY" "bridge_hmac.key not found, skipping HMAC test"
    fi

    if ss -tlnp | awk '{print $4}' | grep -q ':18082\b'; then
        XMR_RESP=$(curl -s --max-time 5 -u "$(cat ${ENGINE_PATH}/vault/encrypted/xmr_rpc_login.vault 2>/dev/null || echo 'user:pass')" \
            -X POST http://127.0.0.1:18082/json_rpc \
            -H "Content-Type: application/json" \
            -d '{"jsonrpc":"2.0","id":"1","method":"get_height"}' 2>/dev/null || echo "")
        if [[ -n "$XMR_RESP" ]] && echo "$XMR_RESP" | grep -q "result"; then
            log_pass "XMR_RPC" "monero-wallet-rpc responding"
        else
            log_warn "XMR_RPC" "monero-wallet-rpc not responding to RPC"
        fi
    fi

    NGINX_RESP=$(curl -s --max-time 5 -k "https://127.0.0.1:8443/health" 2>/dev/null || echo "")
    if [[ -n "$NGINX_RESP" ]]; then
        log_pass "NGINX_8443" "nginx responding on 8443"
    else
        log_warn "NGINX_8443" "nginx not responding on 8443"
    fi
else
    log_warn "HTTP_TESTS" "curl not available, skipping HTTP tests"
fi

if [[ -f /dev/shm/vault.key ]]; then
    perms=$(stat -c '%a' /dev/shm/vault.key 2>/dev/null)
    log_pass "VAULT_KEY_RAM" "Vault key in RAM (${perms})"
else
    log_warn "VAULT_KEY_RAM" "Vault key not in /dev/shm"
fi

if [[ -d /var/log/apache ]]; then
    owner=$(stat -c '%U:%G' /var/log/apache)
    log_pass "LOG_DIR" "Log directory exists (${owner})"
else
    log_warn "LOG_DIR" "/var/log/apache missing"
fi

if command -v getenforce &>/dev/null; then
    SELINUX_STATUS=$(getenforce)
    if [[ "$SELINUX_STATUS" == "Enforcing" ]]; then
        log_pass "SELINUX" "Enforcing"
    else
        log_warn "SELINUX" "${SELINUX_STATUS} (Enforcing recommended)"
    fi
fi

if command -v firewall-cmd &>/dev/null && systemctl is-active --quiet firewalld; then
    if firewall-cmd --zone=wireguard --list-all &>/dev/null; then
        log_pass "FIREWALL" "firewalld wireguard zone configured"
    else
        log_warn "FIREWALL" "firewalld wireguard zone not found"
    fi
else
    log_warn "FIREWALL" "firewalld not running"
fi

if systemctl is-active --quiet s3rv1c3agent; then
    PID=$(systemctl show --property=MainPID --value s3rv1c3agent 2>/dev/null || echo 0)
    if [[ "$PID" -gt 0 ]] && [[ -d "/proc/${PID}" ]]; then
        log_pass "AGENT_PROC" "s3rv1c3agent running (PID ${PID})"
    fi
fi

log_pass "VERIFY_DONE" "${PASS} passed, ${FAIL} failed, ${WARN} warnings"

echo ""
echo "========================================"
echo " Results: ${PASS} PASS | ${FAIL} FAIL | ${WARN} WARN | ${TOTAL} TOTAL"
echo "========================================"

cat > "$REPORT_FILE" <<EOF
{
  "node_id": "${NODE_ID}",
  "node_role": "${NODE_ROLE}",
  "timestamp": "$(date -Iseconds)",
  "summary": {
    "pass": ${PASS},
    "fail": ${FAIL},
    "warn": ${WARN},
    "total": ${TOTAL}
  },
  "health_status": "${HEALTH_STATUS}",
  "passed": $([[ ${FAIL} -eq 0 ]] && echo "true" || echo "false"),
  "results": [
$(printf '%s,\n' "${RESULTS[@]}" | sed '$ s/,$//')
  ]
}
EOF

echo "Report saved: ${REPORT_FILE}"

if [[ $FAIL -eq 0 ]]; then
    echo "VERIFICATION PASSED"
    exit 0
else
    echo "VERIFICATION FAILED (${FAIL} failures)"
    exit 1
fi
