#!/bin/bash

# ============================================================
#            PRO CLOUDIFY CLI
#           TOOLS: DNS & Cache
# ============================================================

set -u

# ------------------------------------------------------------
# Colors
# ------------------------------------------------------------

CYAN='\033[36m'
GREEN='\033[32m'
YELLOW='\033[33m'
RED='\033[31m'
WHITE='\033[37m'
GRAY='\033[90m'
RESET='\033[0m'

# ------------------------------------------------------------
# DNS Providers
# ------------------------------------------------------------

GOOGLE_PRIMARY="8.8.8.8"
GOOGLE_SECONDARY="8.8.4.4"

CLOUDFLARE_PRIMARY="1.1.1.1"
CLOUDFLARE_SECONDARY="1.0.0.1"

QUAD9_PRIMARY="9.9.9.9"
QUAD9_SECONDARY="149.112.112.112"

# ------------------------------------------------------------
# Banner
# ------------------------------------------------------------

show_banner() {
    clear

    echo ""
    echo "============================================"
    echo "            PRO CLOUDIFY CLI"
    echo "           TOOLS: DNS & Cache"
    echo "============================================"
    echo ""
}

# ------------------------------------------------------------
# Detect Active Interface
# ------------------------------------------------------------

get_active_interface() {

    route get default 2>/dev/null |
        awk '/interface:/{print $2; exit}'
}

# ------------------------------------------------------------
# Get Network Service From Interface
# ------------------------------------------------------------

get_network_service() {

    local interface="$1"
    local service
    local device

    while IFS= read -r service; do

        [ -z "$service" ] && continue
        [[ "$service" == \** ]] && continue

        device=$(networksetup -getinfo "$service" 2>/dev/null |
            awk -F': ' '/Device:/{print $2}')

        if [ "$device" = "$interface" ]; then
            echo "$service"
            return 0
        fi

    done < <(
        networksetup -listallnetworkservices 2>/dev/null
    )

    return 1
}

# ------------------------------------------------------------
# Get Current DNS
# ------------------------------------------------------------

get_current_dns() {

    local service="$1"

    networksetup -getdnsservers "$service" 2>/dev/null
}

# ------------------------------------------------------------
# Detect DNS Provider
# ------------------------------------------------------------

detect_provider() {

    local dns="$1"

    if [ -z "$dns" ]; then
        echo "Automatic (DHCP)"
        return 0
    fi

    if echo "$dns" |
        grep -qi "There aren't any DNS Servers set"; then

        echo "Automatic (DHCP)"
        return 0
    fi

    # Google
    if echo "$dns" | grep -q "$GOOGLE_PRIMARY" &&
       echo "$dns" | grep -q "$GOOGLE_SECONDARY"; then

        echo "Google"
        return 0
    fi

    # Cloudflare
    if echo "$dns" | grep -q "$CLOUDFLARE_PRIMARY" &&
       echo "$dns" | grep -q "$CLOUDFLARE_SECONDARY"; then

        echo "Cloudflare"
        return 0
    fi

    # Quad9
    if echo "$dns" | grep -q "$QUAD9_PRIMARY" &&
       echo "$dns" | grep -q "$QUAD9_SECONDARY"; then

        echo "Quad9"
        return 0
    fi

    echo "Custom DNS"
}

# ------------------------------------------------------------
# Show Current DNS
# ------------------------------------------------------------

show_current_dns() {

    local service="$1"
    local interface="$2"

    local dns
    local provider
    local ip

    dns=$(get_current_dns "$service")
    provider=$(detect_provider "$dns")

    ip=$(ipconfig getifaddr "$interface" 2>/dev/null || true)

    echo -e "${YELLOW}Current Network Configuration${RESET}"
    echo ""

    echo -n "  Service   : "
    echo -e "${GREEN}${service}${RESET}"

    echo -n "  Interface : "
    echo -e "${GREEN}${interface}${RESET}"

    echo -n "  IP        : "

    if [ -n "$ip" ]; then
        echo "$ip"
    else
        echo "Unavailable"
    fi

    echo -n "  Provider  : "
    echo -e "${CYAN}${provider}${RESET}"

    if [ "$provider" = "Automatic (DHCP)" ]; then

        echo "  DNS       : Automatic (DHCP)"

    else

        local dns_display
        dns_display=$(echo "$dns" | tr '\n' ' ')

        echo "  DNS       : $dns_display"

    fi

    echo ""
}

# ------------------------------------------------------------
# DNS Menu
# ------------------------------------------------------------

show_dns_menu() {

    echo -e "${YELLOW}Choose DNS Provider${RESET}"
    echo ""

    echo -e "  [1] ${GREEN}Google${RESET}       - 8.8.8.8 / 8.8.4.4"
    echo -e "  [2] ${GREEN}Cloudflare${RESET}   - 1.1.1.1 / 1.0.0.1"
    echo -e "  [3] ${GREEN}Quad9${RESET}        - 9.9.9.9 / 149.112.112.112"
    echo -e "  [4] ${GREEN}Automatic${RESET}    - DHCP"

    echo ""
}

# ------------------------------------------------------------
# Set DNS
# ------------------------------------------------------------

set_dns() {

    local service="$1"
    local choice="$2"

    local primary=""
    local secondary=""

    case "$choice" in

        1)
            primary="$GOOGLE_PRIMARY"
            secondary="$GOOGLE_SECONDARY"
            ;;

        2)
            primary="$CLOUDFLARE_PRIMARY"
            secondary="$CLOUDFLARE_SECONDARY"
            ;;

        3)
            primary="$QUAD9_PRIMARY"
            secondary="$QUAD9_SECONDARY"
            ;;

        4)

            echo -n "Setting DNS to Automatic (DHCP)..."

            if sudo networksetup \
                -setdnsservers "$service" empty \
                >/dev/null 2>&1; then

                echo -e " ${GREEN}OK${RESET}"
                return 0
            fi

            echo -e " ${RED}FAILED${RESET}"
            return 1
            ;;

        *)
            echo -e "${RED}Invalid DNS selection.${RESET}"
            return 1
            ;;
    esac

    echo -n "Setting DNS on ${service}..."

    if sudo networksetup \
        -setdnsservers "$service" \
        "$primary" \
        "$secondary" \
        >/dev/null 2>&1; then

        echo -e " ${GREEN}OK${RESET}"
        return 0
    fi

    echo -e " ${RED}FAILED${RESET}"
    return 1
}

# ------------------------------------------------------------
# Flush DNS Cache
# ------------------------------------------------------------

flush_dns_cache() {

    echo -n "Flushing DNS cache..."

    local failed=0

    sudo dscacheutil -flushcache >/dev/null 2>&1 || failed=1
    sudo killall -HUP mDNSResponder >/dev/null 2>&1 || failed=1

    if [ "$failed" -eq 0 ]; then

        echo -e " ${GREEN}OK${RESET}"
        return 0
    fi

    echo -e " ${RED}FAILED${RESET}"
    return 1
}

# ------------------------------------------------------------
# Verify DNS
# ------------------------------------------------------------

verify_dns() {

    local service="$1"

    local dns
    local provider

    dns=$(get_current_dns "$service")
    provider=$(detect_provider "$dns")

    echo ""
    echo -e "${YELLOW}Verifying DNS configuration...${RESET}"

    sleep 1

    echo ""

    echo -n "  Provider : "
    echo -e "${CYAN}${provider}${RESET}"

    if [ "$provider" = "Automatic (DHCP)" ]; then

        echo "  DNS      : Automatic (DHCP)"

    else

        echo "  DNS      : $(echo "$dns" | tr '\n' ' ')"

    fi
}

# ============================================================
# MAIN
# ============================================================

show_banner

# ------------------------------------------------------------
# Detect Default Route
# ------------------------------------------------------------

echo -e "${YELLOW}Detecting active network service...${RESET}"
echo ""

INTERFACE=$(get_active_interface || true)

if [ -z "$INTERFACE" ]; then

    echo -e "${RED}Unable to detect the active network interface.${RESET}"
    echo ""
    echo "Please check that your Mac has an active Internet connection."
    echo ""

    read -r -p "Press Enter to exit..."
    exit 1
fi

# ------------------------------------------------------------
# Detect Network Service
# ------------------------------------------------------------

SERVICE=$(get_network_service "$INTERFACE" || true)

if [ -z "$SERVICE" ]; then

    echo -e "${RED}Unable to identify the network service.${RESET}"
    echo ""
    echo "Detected interface: $INTERFACE"
    echo ""

    read -r -p "Press Enter to exit..."
    exit 1
fi

# ------------------------------------------------------------
# Display Network
# ------------------------------------------------------------

echo -n "  Service   : "
echo -e "${GREEN}${SERVICE}${RESET}"

echo -n "  Interface : "
echo -e "${GREEN}${INTERFACE}${RESET}"

echo ""

# ------------------------------------------------------------
# Current DNS
# ------------------------------------------------------------

show_current_dns "$SERVICE" "$INTERFACE"

# ------------------------------------------------------------
# Menu
# ------------------------------------------------------------

show_dns_menu

while true; do

    read -r -p "Select [1-4]: " CHOICE

    case "$CHOICE" in
        1|2|3|4)
            break
            ;;

        *)
            echo ""
            echo -e "${RED}Invalid selection. Please choose 1-4.${RESET}"
            echo ""
            ;;
    esac

done

# ------------------------------------------------------------
# Selected Provider
# ------------------------------------------------------------

case "$CHOICE" in

    1)
        SELECTED_NAME="Google"
        SELECTED_PRIMARY="$GOOGLE_PRIMARY"
        SELECTED_SECONDARY="$GOOGLE_SECONDARY"
        ;;

    2)
        SELECTED_NAME="Cloudflare"
        SELECTED_PRIMARY="$CLOUDFLARE_PRIMARY"
        SELECTED_SECONDARY="$CLOUDFLARE_SECONDARY"
        ;;

    3)
        SELECTED_NAME="Quad9"
        SELECTED_PRIMARY="$QUAD9_PRIMARY"
        SELECTED_SECONDARY="$QUAD9_SECONDARY"
        ;;

    4)
        SELECTED_NAME="Automatic (DHCP)"
        SELECTED_PRIMARY=""
        SELECTED_SECONDARY=""
        ;;

esac

# ------------------------------------------------------------
# Show Selection
# ------------------------------------------------------------

echo ""
echo "--------------------------------------------"
echo ""

echo -n "Selected: "
echo -e "${CYAN}${SELECTED_NAME}${RESET}"

if [ -n "$SELECTED_PRIMARY" ]; then

    echo "Primary:   $SELECTED_PRIMARY"
    echo "Secondary: $SELECTED_SECONDARY"

else

    echo "DNS:       Automatic (DHCP)"

fi

echo ""

# ------------------------------------------------------------
# Apply DNS
# ------------------------------------------------------------

if ! set_dns "$SERVICE" "$CHOICE"; then

    echo ""
    echo -e "${RED}DNS change failed.${RESET}"
    echo ""

    read -r -p "Press Enter to exit..."
    exit 1
fi

# ------------------------------------------------------------
# Flush DNS Cache
# ------------------------------------------------------------

flush_dns_cache

# ------------------------------------------------------------
# Verify
# ------------------------------------------------------------

verify_dns "$SERVICE"

# ------------------------------------------------------------
# Final Status
# ------------------------------------------------------------

echo ""
echo "============================================"
echo -e "${GREEN}        DNS CHANGE SUCCESSFUL${RESET}"
echo "============================================"
echo ""

read -r -p "Press Enter to exit..."