#!/bin/bash

# Redundant DNS/NTP Validation Test
# Validates that the host is configured to use the redundant pfv-netinfra-01/02
# pair for name resolution and time, and that both servers actually answer.

set -euo pipefail

PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"

# The authoritative pair (pfv-netinfra-01 / pfv-netinfra-02).
DNS_PRIMARY="192.168.3.252"
DNS_SECONDARY="192.168.3.253"
NTP_PRIMARY="192.168.3.252"
NTP_SECONDARY="192.168.3.253"

RESOLV_CONF="/etc/resolv.conf"
NTP_CONF="/etc/ntpsec/ntp.conf"

# A name every recursive resolver must be able to resolve.
DNS_PROBE_NAME="github.com"

failed=0
have() { command -v "$1" >/dev/null 2>&1; }

# --- Configuration assertions -------------------------------------------------

function test_dns_config_present() {
    echo "🔍 Checking $RESOLV_CONF ..."
    local problems=0

    if [[ -L "$RESOLV_CONF" ]]; then
        echo "❌ $RESOLV_CONF is a symlink (would be overwritten by a resolver manager)"
        ((++problems))
    elif [[ ! -f "$RESOLV_CONF" ]]; then
        echo "❌ $RESOLV_CONF missing"
        ((++problems))
    fi

    for ns in "$DNS_PRIMARY" "$DNS_SECONDARY"; do
        if grep -Eq "^[[:space:]]*nameserver[[:space:]]+$ns" "$RESOLV_CONF" 2>/dev/null; then
            echo "✅ nameserver $ns configured"
        else
            echo "❌ nameserver $ns NOT in $RESOLV_CONF"
            ((++problems))
        fi
    done

    return $problems
}

function test_ntp_config_present() {
    echo "🔍 Checking $NTP_CONF ..."
    if [[ ! -f "$NTP_CONF" ]]; then
        echo "❌ $NTP_CONF missing (is ntpsec installed?)"
        return 1
    fi
    local problems=0
    for s in "$NTP_PRIMARY" "$NTP_SECONDARY"; do
        if grep -Eq "^[[:space:]]*(server|pool)[[:space:]]+$s" "$NTP_CONF"; then
            echo "✅ NTP server $s configured"
        else
            echo "❌ NTP server $s NOT in $NTP_CONF"
            ((++problems))
        fi
    done
    return $problems
}

# --- Functional assertions: each server actually answers ----------------------

function _dns_resolves() {
    # $1 = server ip. Returns 0 if it resolves DNS_PROBE_NAME.
    local server="$1"
    if have dig; then
        dig @"$server" +short +time=4 +tries=1 "$DNS_PROBE_NAME" A 2>/dev/null | grep -Eq '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'
    elif have nslookup; then
        nslookup "$DNS_PROBE_NAME" "$server" 2>/dev/null | grep -Eq 'Address:[[:space:]]*[0-9]'
    elif have host; then
        host "$DNS_PROBE_NAME" "$server" 2>/dev/null | grep -Eq 'has address'
    else
        # Last resort: the resolver itself.
        getent ahostsv4 "$DNS_PROBE_NAME" >/dev/null 2>&1
    fi
}

function test_dns_servers_answer() {
    echo "🔍 Probing DNS servers ..."
    local problems=0
    for ns in "$DNS_PRIMARY" "$DNS_SECONDARY"; do
        if _dns_resolves "$ns"; then
            echo "✅ $ns resolves $DNS_PROBE_NAME"
        else
            echo "❌ $ns did not resolve $DNS_PROBE_NAME"
            ((++problems))
        fi
    done
    return $problems
}

function _ntp_answers() {
    # $1 = server ip. Returns 0 if it responds to a time query.
    local server="$1"
    if have ntpdate; then
        timeout 8 ntpdate -q "$server" 2>/dev/null | grep -Eq 'no-leap|leap'
    elif have sntp; then
        timeout 8 sntp -t 4 "$server" >/dev/null 2>&1
    elif have chronyc; then
        # NTS/chrony not expected here, but be tolerant.
        chronyc -n -h "$server" tracking >/dev/null 2>&1
    else
        return 2  # cannot test
    fi
}

function test_ntp_servers_answer() {
    echo "🔍 Probing NTP servers ..."
    local problems=0
    for s in "$NTP_PRIMARY" "$NTP_SECONDARY"; do
        if _ntp_answers "$s"; then
            echo "✅ NTP $s responds to time query"
        else
            echo "❌ $s did not respond to NTP query"
            ((++problems))
        fi
    done
    return $problems
}

# --- End-to-end: the host is actually USING the pair --------------------------

function test_resolver_endtoend() {
    echo "🔍 End-to-end resolution via $RESOLV_CONF ..."
    if getent ahostsv4 "$DNS_PROBE_NAME" >/dev/null 2>&1; then
        echo "✅ Host resolves $DNS_PROBE_NAME via configured resolver"
        return 0
    else
        echo "❌ Host cannot resolve $DNS_PROBE_NAME via configured resolver"
        return 1
    fi
}

function test_ntp_daemon_peers() {
    echo "🔍 NTP daemon peer list ..."
    local peers
    if have ntpq; then
        peers="$(ntpq -pn 2>/dev/null || true)"
    elif have chronyc; then
        peers="$(chronyc -n sources 2>/dev/null || true)"
    else
        echo "⚠️  No ntpq/chronyc available; skipping daemon peer check"
        return 0
    fi

    local problems=0
    for s in "$NTP_PRIMARY" "$NTP_SECONDARY"; do
        if echo "$peers" | grep -Eq "^\\s*${s//./\\.}"; then
            echo "✅ NTP daemon has peer $s"
        else
            echo "❌ NTP daemon is NOT tracking $s"
            ((++problems))
        fi
    done

    # Sync status is informational only: a freshly started daemon needs several
    # polls before the reach counter stabilises, so we warn rather than fail.
    if echo "$peers" | grep -Eq '\*'; then
        echo "✅ NTP daemon reports a synced peer"
    else
        echo "⚠️  NTP daemon not yet synced (normal for a few minutes after restart)"
    fi
    return $problems
}

# --- Main ---------------------------------------------------------------------

function main() {
    echo "🛰️  Running Redundant DNS/NTP Validation Tests"
    echo "================================================"

    local total_failures=0

    test_dns_config_present        || ((++total_failures))
    test_ntp_config_present        || ((++total_failures))
    test_dns_servers_answer        || ((++total_failures))
    test_ntp_servers_answer        || ((++total_failures))
    test_resolver_endtoend         || ((++total_failures))
    test_ntp_daemon_peers          || ((++total_failures))

    echo "================================================"
    if [[ $total_failures -eq 0 ]]; then
        echo "✅ All redundant DNS/NTP validation tests passed"
        exit 0
    else
        echo "❌ $total_failures redundant DNS/NTP tests failed"
        exit 1
    fi
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi
