#!/usr/bin/env bash
# ============================================================
#  SubHunter Pro
#  Subdomain Discovery, Liveness & Takeover
#  Escalated by @se7endaysecc
# ============================================================

set -euo pipefail

# ---------- Bash Version Check ----------
if [[ ${BASH_VERSINFO[0]} -lt 4 ]]; then
    echo -e "\033[0;31m[!] Bash 4+ required. Current: $BASH_VERSION\033[0m"
    echo -e "\033[1;33m    macOS: brew install bash\033[0m"
    echo -e "\033[1;33m    Linux: sudo apt-get install bash (or similar)\033[0m"
    exit 1
fi

# ---------- Color ----------
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; MAGENTA='\033[0;35m'; BOLD='\033[1m'; NC='\033[0m'

TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# ---------- Core Paths ----------
TOOLS_DIR="${TOOLS_DIR:-$HOME/.subhunter_tools}"
GO_PATH="${GOPATH:-$HOME/go}"
export PATH="$TOOLS_DIR:$GO_PATH/bin:/usr/local/bin:$PATH"

# ---------- Traps ----------
TMPDIR=$(mktemp -d) || { echo -e "${RED}[!] Failed to create temp directory${NC}"; exit 1; }
cleanup() { rm -rf "$TMPDIR" 2>/dev/null || true; }
trap cleanup EXIT INT TERM

# ---------- Rate Limiting ----------
RATE_LIMIT="${RATE_LIMIT:-150}"
rate_sleep() {
    local rate="${RATE_LIMIT:-150}"
    if [[ "$rate" -lt 1 ]]; then
        rate=1
    fi
    local sleep_time
    sleep_time=$(echo "scale=2; 60.0 / $rate" | bc 2>/dev/null || echo "0.4")
    sleep "$sleep_time"
}

# ---------- Log ----------
LOGFILE=""
log() {
    echo -e "$1"
    [[ -n "$LOGFILE" ]] && echo -e "$(date '+%H:%M:%S') $1" | sed 's/\x1B\[[0-9;]*m//g' >> "$LOGFILE"
}

# ---------- Banner ----------
banner() {
    echo -e "${CYAN}${BOLD}"
    cat << 'EOF'
   ___      __   __             __
  / __/_ _ / /  / /  _  _ ___  / /____ ____
 _\ \/ // / _ \/ _ \/ // / _ \/ __/ -_) __/
/___/\_,_/_.__/_//_/\_,_/_//_/\__/\__/_/

  SubHunter Pro
  Subdomain Discovery | Liveness | Takeover
EOF
    echo -e "${NC}"
}

# ---------- Usage ----------
usage() {
    cat << EOF
${BOLD}Usage:${NC}
  $0 -d <domain> [options]

${BOLD}Options:${NC}
  -d <domain>       Target domain (required)
  -o <dir>          Output directory (default: ./subhunter_results/<domain>)
  -w <wordlist>     Custom wordlist for brute-force DNS
  -t <threads>      Thread count (default: 50)
  -r                Resolve only — skip takeover checks
  -s                Skip subdomain enumeration, use existing file with -f
  -f <file>         Use an existing subdomain list file
  -p                Enable subdomain permutation/alteration
  -q                Quiet mode — minimal output (only findings & summary)
  -k                Keep individual source files (default: auto-clean)
  --rate-limit N    Max requests per minute (default: 150)
  -h                Show this help

${BOLD}Examples:${NC}
  $0 -d example.com
  $0 -d example.com -t 100 -p -o /tmp/results
  $0 -d example.com -s -f my_subs.txt -q --rate-limit 60

EOF
    exit 0
}

# ---------- Tool Management ----------
TOOL_REGISTRY=(
    "subfinder:github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest"
    "httpx:github.com/projectdiscovery/httpx/cmd/httpx@latest"
    "dnsx:github.com/projectdiscovery/dnsx/cmd/dnsx@latest"
    "nuclei:github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest"
    "assetfinder:github.com/tomnomnom/assetfinder@latest"
    "amass:github.com/owasp-amass/amass/v4/...@master"
    "subjack:github.com/haccer/subjack@latest"
    "anew:github.com/tomnomnom/anew@latest"
    "gowitness:github.com/sensepost/gowitness@latest"
    "naabu:github.com/projectdiscovery/naabu/v2/cmd/naabu@latest"
    "mapcidr:github.com/projectdiscovery/mapcidr/cmd/mapcidr@latest"
)

check_tool() {
    local name="$1"
    if command -v "$name" &>/dev/null; then
        [[ "${QUIET:-false}" != true ]] && echo -e "  ${GREEN}[+]${NC} $name"
        return 0
    else
        [[ "${QUIET:-false}" != true ]] && echo -e "  ${RED}[-]${NC} $name — not installed"
        return 1
    fi
}

install_missing() {
    [[ "${QUIET:-false}" != true ]] && echo -e "\n${YELLOW}[*] Install missing tools? (y/n)${NC}"
    read -r ans
    [[ "$ans" != "y" ]] && { echo "Exiting."; exit 1; }

    if ! command -v go &>/dev/null; then
        echo -e "${RED}[!] Go is required. Install from https://go.dev/dl/${NC}"
        exit 1
    fi

    mkdir -p "$TOOLS_DIR"
    export GOPATH="$GO_PATH"

    echo -e "${CYAN}[*] Installing missing tools...${NC}"
    for entry in "${TOOL_REGISTRY[@]}"; do
        local bin="${entry%%:*}"
        local pkg="${entry#*:}"
        command -v "$bin" &>/dev/null && continue
        echo -e "  ${YELLOW}→${NC} Installing $bin ..."
        go install "$pkg" 2>/dev/null || echo -e "  ${RED}✗${NC} $bin failed"
        [[ -f "$GO_PATH/bin/$bin" ]] && ln -sf "$GO_PATH/bin/$bin" "$TOOLS_DIR/$bin"
    done

    # Install system packages
    if ! command -v jq &>/dev/null; then
        echo -e "  ${YELLOW}→${NC} Installing jq..."
        if command -v apt-get &>/dev/null; then
            sudo apt-get install -y jq 2>/dev/null || true
        elif command -v brew &>/dev/null; then
            brew install jq 2>/dev/null || true
        elif command -v yum &>/dev/null; then
            sudo yum install -y jq 2>/dev/null || true
        fi
    fi

    if ! command -v host &>/dev/null || ! command -v dig &>/dev/null; then
        echo -e "  ${YELLOW}→${NC} Installing dnsutils (host/dig)..."
        if command -v apt-get &>/dev/null; then
            sudo apt-get install -y dnsutils 2>/dev/null || true
        elif command -v brew &>/dev/null; then
            brew install bind 2>/dev/null || true
        elif command -v yum &>/dev/null; then
            sudo yum install -y bind-utils 2>/dev/null || true
        fi
    fi

    echo -e "${GREEN}[+] Installation complete.${NC}"
}

# ---------- Parallel Runner ----------
parallel_run() {
    local max_jobs="$1"
    shift
    local -a cmds=("$@")
    local running=0
    local pids=()

    if [[ ${#cmds[@]} -eq 0 ]]; then
        return
    fi

    for cmd in "${cmds[@]}"; do
        while [[ "$running" -ge "$max_jobs" ]]; do
            for pid in "${pids[@]}"; do
                kill -0 "$pid" 2>/dev/null || {
                    wait "$pid" 2>/dev/null || true
                    running=$((running - 1))
                }
            done
            pids=($(jobs -p 2>/dev/null || true))
            running=${#pids[@]}
            [[ "$running" -ge "$max_jobs" ]] && sleep 0.2
        done
        eval "$cmd" &
        pids+=($!)
        running=$((running + 1))
    done
    wait 2>/dev/null || true
}

# ---------- Wildcard Detection ----------
detect_wildcard() {
    local domain="$1"
    local resolved_file="$2"
    local output_dir="$3"

    log "${CYAN}[*] Checking for wildcard DNS...${NC}"

    if [[ ! -f "$resolved_file" ]]; then
        log "${YELLOW}[!] No resolved file to check for wildcard${NC}"
        return 1
    fi

    # Ensure backup exists before we modify resolved_file
    if [[ ! -f "$output_dir/resolved_raw.txt" ]]; then
        cp "$resolved_file" "$output_dir/resolved_raw.txt" 2>/dev/null || true
    fi

    local random_sub="wildcard-check-$(date +%s%N)-${RANDOM}.${domain}"
    local wildcard_ip
    wildcard_ip=$(dig +short A "$random_sub" 2>/dev/null | head -1)

    if [[ -n "$wildcard_ip" ]]; then
        log "${YELLOW}[!] Wildcard DNS detected: *.${domain} → ${wildcard_ip}${NC}"
        log "${YELLOW}[!] Filtering false positives...${NC}"

        local filtered="$output_dir/resolved_filtered.txt"
        grep -v "\[$wildcard_ip\]" "$resolved_file" > "$filtered" 2>/dev/null || true

        if [[ -s "$filtered" ]]; then
            mv "$filtered" "$resolved_file"
        else
            # All entries were wildcard — leave empty
            > "$resolved_file"
            rm -f "$filtered"
        fi

        local original_count filtered_count removed
        original_count=$(wc -l < "$output_dir/resolved_raw.txt" 2>/dev/null || echo 0)
        filtered_count=$(wc -l < "$resolved_file" 2>/dev/null || echo 0)
        removed=$((original_count - filtered_count))
        log "${YELLOW}[!] Removed $removed wildcard-induced false positives${NC}"

        echo "$wildcard_ip" > "$output_dir/wildcard_ip.txt"
        return 0
    else
        log "${GREEN}[+] No wildcard DNS detected${NC}"
        return 1
    fi
}

# ---------- DNS Zone Transfer Check ----------
check_zone_transfer() {
    local domain="$1"
    local output_dir="$2"
    local zt_file="$output_dir/zone_transfer.txt"

    > "$zt_file"

    if ! command -v dig &>/dev/null; then
        log "${YELLOW}[!] dig not available — skipping zone transfer check${NC}"
        return
    fi

    log "${CYAN}[*] Checking for DNS zone transfer (AXFR)...${NC}"

    local nameservers
    nameservers=$(dig +short NS "$domain" 2>/dev/null || true)

    if [[ -z "$nameservers" ]]; then
        log "${YELLOW}[!] No nameservers found for zone transfer check${NC}"
        return
    fi

    while IFS= read -r ns; do
        [[ -z "$ns" ]] && continue
        rate_sleep
        local result
        result=$(dig axfr "$domain" @"$ns" 2>/dev/null || true)
        if echo "$result" | grep -qi "Transfer failed"; then
            [[ "$QUIET" != true ]] && log "  ${GREEN}[SECURE]${NC} $ns — zone transfer denied"
        elif echo "$result" | grep -q ";;"; then
            echo "$ns" >> "$zt_file"
            log "${RED}[VULNERABLE]${NC} $ns — zone transfer ALLOWED!"
            echo "$result" >> "${zt_file}.data"
        fi
    done <<< "$nameservers"

    if [[ ! -s "$zt_file" ]]; then
        [[ "$QUIET" != true ]] && log "${GREEN}[+] All nameservers secure against zone transfer${NC}"
    fi
}

# ---------- Permutation Engine ----------
generate_permutations() {
    local domain="$1"
    local subdomains_file="$2"
    local output_file="$3"
    local threads="$4"

    if [[ ! -s "$subdomains_file" ]]; then
        log "${YELLOW}[!] No subdomains to permute${NC}"
        return
    fi

    log "${CYAN}[*] Generating subdomain permutations...${NC}"

    local prefixes
    prefixes=$(grep -oE '^[^.]+' "$subdomains_file" 2>/dev/null | sort -u)

    if [[ -z "$prefixes" ]]; then
        log "${YELLOW}[!] No prefixes to permute${NC}"
        return
    fi

    local perm_file="$TMPDIR/perms.$$.txt"
    > "$perm_file"

    local -a ALTS=(
        "admin-{prefix}" "{prefix}-api" "{prefix}2" "{prefix}-dev"
        "dev-{prefix}" "{prefix}-staging" "staging-{prefix}"
        "{prefix}-test" "test-{prefix}" "{prefix}-old"
        "{prefix}-new" "uat-{prefix}" "{prefix}-uat"
        "{prefix}-beta" "beta-{prefix}" "{prefix}-v2"
        "{prefix}-backup" "backup-{prefix}" "{prefix}-internal"
        "{prefix}-prod" "prod-{prefix}" "{prefix}-cdn"
    )

    while IFS= read -r prefix; do
        [[ -z "$prefix" ]] && continue
        for alt_template in "${ALTS[@]}"; do
            local alt="${alt_template//\{prefix\}/$prefix}"
            echo "${alt}.${domain}"
        done
    done <<< "$prefixes" > "$perm_file"

    # Numbered variants
    while IFS= read -r prefix; do
        [[ -z "$prefix" ]] && continue
        for i in 1 2 3; do
            echo "${prefix}${i}.${domain}"
        done
    done <<< "$prefixes" >> "$perm_file"

    local total_perms
    total_perms=$(wc -l < "$perm_file" 2>/dev/null || echo 0)
    log "${GREEN}[+] Generated $total_perms permutations${NC}"

    if command -v dnsx &>/dev/null && [[ -s "$perm_file" ]]; then
        log "${CYAN}[*] Resolving permutations...${NC}"
        dnsx -l "$perm_file" -silent -threads "$threads" -o "$output_file" 2>/dev/null || true
        local resolved
        resolved=$(wc -l < "$output_file" 2>/dev/null || echo 0)
        log "${GREEN}[+] Permutations resolved: $resolved${NC}"
    fi
}

# ==================================================================
#  PARSE ARGS
# ==================================================================
DOMAIN=""
OUTDIR=""
WORDLIST=""
THREADS=50
RESOLVE_ONLY=false
SKIP_ENUM=false
SUBFILE=""
QUIET=false
KEEP_SRC=false
PERMUTE=false

while [[ $# -gt 0 ]]; do
    case "$1" in
        -d) DOMAIN="$2"; shift 2 ;;
        -o) OUTDIR="$2"; shift 2 ;;
        -w) WORDLIST="$2"; shift 2 ;;
        -t) THREADS="$2"; shift 2 ;;
        -r) RESOLVE_ONLY=true; shift ;;
        -s) SKIP_ENUM=true; shift ;;
        -f) SUBFILE="$2"; shift 2 ;;
        -p) PERMUTE=true; shift ;;
        -q) QUIET=true; shift ;;
        -k) KEEP_SRC=true; shift ;;
        --rate-limit) RATE_LIMIT="$2"; shift 2 ;;
        -h) usage ;;
        *) usage ;;
    esac
done

# ---- VALIDASI ----
[[ -z "$DOMAIN" ]] && { echo -e "${RED}[!] -d <domain> is required${NC}"; usage; }

# Validasi file jika skip enum
if [[ "$SKIP_ENUM" == true && -n "$SUBFILE" ]]; then
    if [[ ! -f "$SUBFILE" ]]; then
        echo -e "${RED}[!] File not found: $SUBFILE${NC}"
        exit 1
    fi
fi

# Validasi wordlist
if [[ -n "$WORDLIST" && ! -f "$WORDLIST" ]]; then
    echo -e "${YELLOW}[!] Wordlist not found: $WORDLIST — proceeding without brute-force${NC}"
    WORDLIST=""
fi

[[ -z "$OUTDIR" ]] && OUTDIR="./subhunter_results/${DOMAIN}"
mkdir -p "$OUTDIR"
LOGFILE="$OUTDIR/subhunter.log"

# ==================================================================
#  MAIN
# ==================================================================
[[ "$QUIET" != true ]] && banner
log "${BOLD}Target:${NC}  $DOMAIN"
log "${BOLD}Output:${NC}  $OUTDIR"
log "${BOLD}Rate limit:${NC} $RATE_LIMIT req/min"
log "${BOLD}Time:${NC}    $(date)"
log ""

# ---------- Dependency Check ----------
[[ "$QUIET" != true ]] && log "${CYAN}[*] Checking tools...${NC}"
MISSING=0
for tool in subfinder amass assetfinder httpx dnsx nuclei subjack anew jq curl dig host; do
    check_tool "$tool" || MISSING=1
done
[[ "$MISSING" -eq 1 ]] && install_missing
[[ "$QUIET" != true ]] && echo ""

# ==================================================================
#  PHASE 0: PRE-FLIGHT CHECKS
# ==================================================================
[[ "$QUIET" != true ]] && log "${MAGENTA}${BOLD}═══ PRE-FLIGHT CHECKS ═══${NC}"

check_zone_transfer "$DOMAIN" "$OUTDIR"
[[ "$QUIET" != true ]] && echo ""

# ==================================================================
#  PHASE 1: SUBDOMAIN ENUMERATION
# ==================================================================
ALL_SUBS="$OUTDIR/all_subdomains.txt"

if [[ "$SKIP_ENUM" == true && -n "$SUBFILE" ]]; then
    log "${YELLOW}[*] Skipping enumeration — using $SUBFILE${NC}"
    cp "$SUBFILE" "$ALL_SUBS"
else
    [[ "$QUIET" != true ]] && log "${MAGENTA}${BOLD}═══ PHASE 1: Subdomain Enumeration ═══${NC}"

    enum_jobs=()

    # 1 - subfinder
    if command -v subfinder &>/dev/null; then
        enum_jobs+=("subfinder -d '$DOMAIN' -silent -all -o '$OUTDIR/subfinder.txt' 2>/dev/null")
    fi

    # 2 - amass passive
    if command -v amass &>/dev/null; then
        enum_jobs+=("timeout 300 amass enum -passive -d '$DOMAIN' -o '$OUTDIR/amass.txt' 2>/dev/null || true")
    fi

    # 3 - assetfinder
    if command -v assetfinder &>/dev/null; then
        enum_jobs+=("assetfinder --subs-only '$DOMAIN' > '$OUTDIR/assetfinder.txt' 2>/dev/null")
    fi

    # 4 - crt.sh
    enum_jobs+=("curl -s --connect-timeout 15 --max-time 30 'https://crt.sh/?q=%25.$DOMAIN&output=json' 2>/dev/null | jq -r '.[].name_value // empty' 2>/dev/null | sed 's/\\\n/\\\n/g' | sort -u > '$OUTDIR/crtsh.txt' || true")

    # 5 - certspotter
    enum_jobs+=("curl -s --connect-timeout 15 --max-time 30 'https://api.certspotter.com/v1/issuances?domain=$DOMAIN&include_subdomains=true&expand=dns_names' 2>/dev/null | jq -r '.[].dns_names[] // empty' 2>/dev/null | grep -E '\.$DOMAIN$' | sort -u > '$OUTDIR/certspotter.txt' || true")

    # 6 - wordlist bruteforce
    if [[ -n "$WORDLIST" ]] && command -v dnsx &>/dev/null; then
        enum_jobs+=("awk '{print \$1\".$DOMAIN\"}' '$WORDLIST' | dnsx -silent -threads $THREADS -o '$OUTDIR/brute.txt' 2>/dev/null || true")
    fi

    # Execute enumeration
    if [[ ${#enum_jobs[@]} -gt 0 ]]; then
        [[ "$QUIET" != true ]] && log "${CYAN}[*] Running enumeration sources in parallel...${NC}"
        parallel_run 3 "${enum_jobs[@]}"
    fi

    # Count sources
    for src in subfinder amass assetfinder crtsh certspotter brute; do
        if [[ -f "$OUTDIR/${src}.txt" ]]; then
            c=$(wc -l < "$OUTDIR/${src}.txt" 2>/dev/null || echo 0)
            [[ "$QUIET" != true ]] && log "${GREEN}[+] ${src}: $c subdomains${NC}"
        fi
    done
    [[ "$QUIET" != true ]] && echo ""

    # ---- Merge & Deduplicate ----
    [[ "$QUIET" != true ]] && log "${CYAN}[*] Merging and deduplicating...${NC}"

    if command -v anew &>/dev/null; then
        > "$TMPDIR/merged.$$.tmp"
        for src in subfinder amass assetfinder crtsh certspotter brute; do
            [[ -f "$OUTDIR/${src}.txt" ]] && anew "$OUTDIR/${src}.txt" >> "$TMPDIR/merged.$$.tmp" 2>/dev/null || true
        done
        grep -E "\.${DOMAIN//./\\.}$" "$TMPDIR/merged.$$.tmp" 2>/dev/null \
            | tr '[:upper:]' '[:lower:]' | sort -u > "$ALL_SUBS"
    else
        cat "$OUTDIR"/subfinder.txt "$OUTDIR"/amass.txt "$OUTDIR"/assetfinder.txt \
            "$OUTDIR"/crtsh.txt "$OUTDIR"/certspotter.txt "$OUTDIR"/brute.txt 2>/dev/null \
            | grep -E "\.${DOMAIN//./\\.}$" \
            | tr '[:upper:]' '[:lower:]' \
            | sort -u > "$ALL_SUBS"
    fi

    TOTAL=$(wc -l < "$ALL_SUBS" 2>/dev/null || echo 0)
    log "${GREEN}${BOLD}[+] Total unique subdomains: $TOTAL${NC}"

    # ---- Permutation Engine ----
    if [[ "$PERMUTE" == true ]]; then
        generate_permutations "$DOMAIN" "$ALL_SUBS" "$OUTDIR/permutations.txt" "$THREADS"

        if [[ -s "$OUTDIR/permutations.txt" ]]; then
            log "${CYAN}[*] Merging permutations into main list...${NC}"
            cat "$ALL_SUBS" "$OUTDIR/permutations.txt" | sort -u > "$TMPDIR/with_perms.$$.tmp"
            mv "$TMPDIR/with_perms.$$.tmp" "$ALL_SUBS"
            TOTAL=$(wc -l < "$ALL_SUBS")
            log "${GREEN}[+] Total subdomains after permutations: $TOTAL${NC}"
        fi
    fi

    # Cleanup source files
    [[ "$KEEP_SRC" != true ]] && rm -f "$OUTDIR"/subfinder.txt "$OUTDIR"/amass.txt \
        "$OUTDIR"/assetfinder.txt "$OUTDIR"/crtsh.txt "$OUTDIR"/certspotter.txt \
        "$OUTDIR"/brute.txt
fi

[[ "$QUIET" != true ]] && echo ""

# ==================================================================
#  PHASE 2: DNS RESOLUTION & LIVENESS
# ==================================================================
[[ "$QUIET" != true ]] && log "${MAGENTA}${BOLD}═══ PHASE 2: DNS Resolution & Liveness ═══${NC}"

LIVE_SUBS="$OUTDIR/live_subdomains.txt"
RESOLVED="$OUTDIR/resolved.txt"
CNAME_FILE="$OUTDIR/cnames.txt"
RESOLVED_AAAA="$OUTDIR/resolved_aaaa.txt"

if command -v dnsx &>/dev/null; then
    [[ "$QUIET" != true ]] && log "${CYAN}[*] Resolving DNS (A records)...${NC}"
    dnsx -l "$ALL_SUBS" -silent -a -resp -threads "$THREADS" -o "$RESOLVED" 2>/dev/null
    RES_COUNT=$(wc -l < "$RESOLVED" 2>/dev/null || echo 0)

    # Backup raw for wildcard detection
    cp "$RESOLVED" "$OUTDIR/resolved_raw.txt" 2>/dev/null || true

    [[ "$QUIET" != true ]] && log "${GREEN}[+] Resolved A records: $RES_COUNT${NC}"

    # ---- Wildcard Detection ----
    detect_wildcard "$DOMAIN" "$RESOLVED" "$OUTDIR"
    RES_COUNT=$(wc -l < "$RESOLVED" 2>/dev/null || echo 0)
    [[ "$QUIET" != true ]] && log "${GREEN}[+] Resolved after wildcard filter: $RES_COUNT${NC}"

    # ---- IPv6 Resolution ----
    [[ "$QUIET" != true ]] && log "${CYAN}[*] Resolving DNS (AAAA / IPv6)...${NC}"
    dnsx -l "$ALL_SUBS" -silent -aaaa -resp -threads "$THREADS" -o "$RESOLVED_AAAA" 2>/dev/null
    AAAA_COUNT=$(wc -l < "$RESOLVED_AAAA" 2>/dev/null || echo 0)
    [[ "$QUIET" != true ]] && log "${GREEN}[+] Resolved AAAA records: $AAAA_COUNT${NC}"

    # ---- CNAME Records ----
    [[ "$QUIET" != true ]] && log "${CYAN}[*] Collecting CNAME records...${NC}"
    dnsx -l "$ALL_SUBS" -silent -cname -resp -threads "$THREADS" -o "$CNAME_FILE" 2>/dev/null
    CNAME_COUNT=$(wc -l < "$CNAME_FILE" 2>/dev/null || echo 0)
    [[ "$QUIET" != true ]] && log "${GREEN}[+] CNAME records: $CNAME_COUNT${NC}"
else
    log "${YELLOW}[!] dnsx not found — using dig fallback (slower)${NC}"
    > "$RESOLVED"; > "$RESOLVED_AAAA"; > "$CNAME_FILE"
    while IFS= read -r sub; do
        rate_sleep
        ip=$(dig +short A "$sub" 2>/dev/null | head -1)
        [[ -n "$ip" ]] && echo "$sub [$ip]" >> "$RESOLVED"
        ip6=$(dig +short AAAA "$sub" 2>/dev/null | head -1)
        [[ -n "$ip6" ]] && echo "$sub [$ip6]" >> "$RESOLVED_AAAA"
        cname=$(dig +short CNAME "$sub" 2>/dev/null | head -1)
        [[ -n "$cname" ]] && echo "$sub [$cname]" >> "$CNAME_FILE"
    done < "$ALL_SUBS"
fi

# ---- HTTP Liveness ----
if command -v httpx &>/dev/null; then
    [[ "$QUIET" != true ]] && log "${CYAN}[*] Probing HTTP/HTTPS liveness...${NC}"
    httpx -l "$ALL_SUBS" -silent -threads "$THREADS" \
        -status-code -title -tech-detect -follow-redirects \
        -o "$OUTDIR/httpx_full.txt" 2>/dev/null

    # grep -oE for macOS compatibility
    grep -oE 'https?://[^ ]+' "$OUTDIR/httpx_full.txt" > "$LIVE_SUBS" 2>/dev/null || true
    LIVE_COUNT=$(wc -l < "$LIVE_SUBS" 2>/dev/null || echo 0)
    [[ "$QUIET" != true ]] && log "${GREEN}${BOLD}[+] Live subdomains (HTTP): $LIVE_COUNT${NC}"
else
    log "${YELLOW}[!] httpx not found — using curl fallback${NC}"
    > "$LIVE_SUBS"
    while IFS= read -r sub; do
        rate_sleep
        for scheme in https http; do
            status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "${scheme}://$sub" 2>/dev/null || true)
            if [[ "$status" -gt 0 && "$status" -lt 500 ]]; then
                echo "${scheme}://$sub [$status]" >> "$LIVE_SUBS"
                break
            fi
        done
    done < "$ALL_SUBS"
fi

[[ "$QUIET" != true ]] && echo ""

# ---- Port Scanning (naabu) ----
if command -v naabu &>/dev/null && [[ -s "$LIVE_SUBS" || -s "$RESOLVED" ]]; then
    [[ "$QUIET" != true ]] && log "${CYAN}[*] Scanning top 100 ports with naabu...${NC}"
    naabu -list "$ALL_SUBS" -top-ports 100 -silent -threads "$THREADS" \
        -o "$OUTDIR/ports.txt" 2>/dev/null || true
    PORT_COUNT=$(wc -l < "$OUTDIR/ports.txt" 2>/dev/null || echo 0)
    [[ "$QUIET" != true ]] && log "${GREEN}[+] Open ports detected: $PORT_COUNT${NC}"
    [[ "$QUIET" != true ]] && echo ""
fi

# ---- Screenshots (gowitness) ----
if command -v gowitness &>/dev/null && [[ -s "$LIVE_SUBS" ]]; then
    [[ "$QUIET" != true ]] && log "${CYAN}[*] Taking screenshots with gowitness...${NC}"
    mkdir -p "$OUTDIR/screenshots"
    gowitness file -f "$LIVE_SUBS" --destination "$OUTDIR/screenshots" \
        --threads "$THREADS" 2>/dev/null || true
    SS_COUNT=$(ls "$OUTDIR/screenshots"/*.png 2>/dev/null | wc -l || echo 0)
    [[ "$QUIET" != true ]] && log "${GREEN}[+] Screenshots taken: $SS_COUNT${NC}"
    [[ "$QUIET" != true ]] && echo ""
fi

# ==================================================================
#  PHASE 3: SUBDOMAIN TAKEOVER DETECTION
# ==================================================================
if [[ "$RESOLVE_ONLY" == true ]]; then
    log "${YELLOW}[*] Resolve-only mode — skipping takeover checks${NC}"
else
    [[ "$QUIET" != true ]] && log "${MAGENTA}${BOLD}═══ PHASE 3: Subdomain Takeover Detection ═══${NC}"

    TAKEOVER_FILE="$OUTDIR/takeover_vulnerable.txt"
    > "$TAKEOVER_FILE"

    # ---- nuclei ----
    if command -v nuclei &>/dev/null; then
        [[ "$QUIET" != true ]] && log "${CYAN}[*] Running nuclei takeover templates...${NC}"
        nuclei -l "$ALL_SUBS" -t http/takeovers/ -silent \
            -o "$OUTDIR/nuclei_takeover.txt" -threads "$THREADS" 2>/dev/null || true
        if [[ -s "$OUTDIR/nuclei_takeover.txt" ]]; then
            cat "$OUTDIR/nuclei_takeover.txt" >> "$TAKEOVER_FILE"
            NUCLEI_HIT=$(wc -l < "$OUTDIR/nuclei_takeover.txt")
            log "${RED}${BOLD}[!] nuclei found $NUCLEI_HIT potential takeovers!${NC}"
        else
            [[ "$QUIET" != true ]] && log "${GREEN}[+] nuclei: no takeovers detected${NC}"
        fi
    fi

    # ---- subjack ----
    if command -v subjack &>/dev/null; then
        [[ "$QUIET" != true ]] && log "${CYAN}[*] Running subjack...${NC}"
        FP_PATH=$(find "$GO_PATH/pkg/mod/github.com/haccer" -name "fingerprints.json" 2>/dev/null | head -1)
        if [[ -n "$FP_PATH" ]]; then
            subjack -w "$ALL_SUBS" -t "$THREADS" -timeout 30 \
                -c "$FP_PATH" -ssl -o "$OUTDIR/subjack.txt" -v 2>/dev/null || true
        else
            subjack -w "$ALL_SUBS" -t "$THREADS" -timeout 30 \
                -ssl -o "$OUTDIR/subjack.txt" -v 2>/dev/null || true
        fi
        if [[ -s "$OUTDIR/subjack.txt" ]]; then
            cat "$OUTDIR/subjack.txt" >> "$TAKEOVER_FILE"
            SJ_HIT=$(wc -l < "$OUTDIR/subjack.txt")
            log "${RED}${BOLD}[!] subjack found $SJ_HIT potential takeovers!${NC}"
        else
            [[ "$QUIET" != true ]] && log "${GREEN}[+] subjack: no takeovers detected${NC}"
        fi
    fi

    # ---- CNAME-based Dangling Detection (macOS compatible) ----
    [[ "$QUIET" != true ]] && log "${CYAN}[*] Analyzing CNAME records for dangling pointers...${NC}"
    DANGLING_FILE="$OUTDIR/dangling_cnames.txt"
    > "$DANGLING_FILE"

    # Portable array: "domain:service_name"
    TAKEOVER_ENTRIES=(
        "s3.amazonaws.com:AWS S3 Bucket"
        "elasticbeanstalk.com:AWS Elastic Beanstalk"
        "herokuapp.com:Heroku App"
        "herokudns.com:Heroku DNS"
        "cloudfront.net:AWS CloudFront"
        "azurewebsites.net:Azure App Service"
        "blob.core.windows.net:Azure Blob Storage"
        "cloudapp.net:Azure Cloud Services"
        "trafficmanager.net:Azure Traffic Manager"
        "azure-api.net:Azure API Management"
        "azurefd.net:Azure Front Door"
        "github.io:GitHub Pages"
        "bitbucket.io:Bitbucket Pages"
        "wordpress.com:WordPress.com"
        "pantheon.io:Pantheon"
        "ghost.io:Ghost"
        "ghost.org:Ghost (Pro)"
        "myshopify.com:Shopify"
        "surge.sh:Surge.sh"
        "netlify.app:Netlify"
        "netlify.com:Netlify"
        "fly.dev:Fly.io"
        "webflow.io:Webflow"
        "statuspage.io:Atlassian Statuspage"
        "freshdesk.com:Freshdesk"
        "zendesk.com:Zendesk"
        "helpjuice.com:Helpjuice"
        "helpscoutdocs.com:Help Scout Docs"
        "readme.io:ReadMe.io"
        "unbounce.com:Unbounce"
        "uservoice.com:UserVoice"
        "wufoo.com:Wufoo"
        "ngrok.io:ngrok"
        "pingdom.com:Pingdom"
        "uptimerobot.com:UptimeRobot"
        "strikingly.com:Strikingly"
        "cargocollective.com:Cargo Collective"
        "smugmug.com:SmugMug"
        "tictail.com:Tictail"
        "tilda.ws:Tilda"
        "launchrock.com:LaunchRock"
        "simplebooklet.com:Simplebooklet"
        "pages.dev:Cloudflare Pages"
        "r2.dev:Cloudflare R2"
        "vercel.app:Vercel"
        "onrender.com:Render"
        "railway.app:Railway"
        "firebaseapp.com:Firebase"
        "web.app:Firebase Web"
        "appspot.com:Google App Engine"
        "azureedge.net:Azure CDN"
    )

    if [[ -s "$CNAME_FILE" ]]; then
        while IFS= read -r line; do
            subdomain=$(echo "$line" | awk '{print $1}')
            cname=$(echo "$line" | grep -oE '\[.*?\]' | tr -d '[]')
            [[ -z "$cname" || "$cname" == "[]" ]] && continue

            for entry in "${TAKEOVER_ENTRIES[@]}"; do
                sig="${entry%%:*}"
                label="${entry#*:}"
                if echo "$cname" | grep -qiF "$sig"; then
                    if ! host "$cname" &>/dev/null; then
                        echo -e "${RED}[VULNERABLE]${NC} $subdomain → $cname ($label)" \
                            | tee -a "$DANGLING_FILE"
                    else
                        http_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "https://$subdomain" 2>/dev/null || echo "000")
                        if [[ "$http_code" == "404" || "$http_code" == "000" ]]; then
                            echo -e "${YELLOW}[POSSIBLE]${NC}  $subdomain → $cname ($label, HTTP $http_code)" \
                                | tee -a "$DANGLING_FILE"
                        fi
                    fi
                    break
                fi
            done
        done < "$CNAME_FILE"

        if [[ -s "$DANGLING_FILE" ]]; then
            cat "$DANGLING_FILE" >> "$TAKEOVER_FILE"
            DANG_COUNT=$(wc -l < "$DANGLING_FILE")
            log "${RED}${BOLD}[!] Found $DANG_COUNT dangling CNAME(s)!${NC}"
        else
            [[ "$QUIET" != true ]] && log "${GREEN}[+] No dangling CNAMEs detected${NC}"
        fi
    else
        [[ "$QUIET" != true ]] && log "${YELLOW}[!] No CNAME data available — skipping${NC}"
    fi

    # ---- Takeover Summary ----
    [[ "$QUIET" != true ]] && echo ""
    if [[ -s "$TAKEOVER_FILE" ]]; then
        sort -u "$TAKEOVER_FILE" -o "$TAKEOVER_FILE"
        TK_TOTAL=$(wc -l < "$TAKEOVER_FILE")
        log "${RED}${BOLD}[!!!] TOTAL POTENTIAL TAKEOVERS: $TK_TOTAL${NC}"
        log "${RED}Review: $TAKEOVER_FILE${NC}"
    else
        log "${GREEN}[+] No subdomain takeover vulnerabilities detected${NC}"
    fi

    [[ "$KEEP_SRC" != true ]] && rm -f "$OUTDIR"/nuclei_takeover.txt "$OUTDIR"/subjack.txt "$OUTDIR"/dangling_cnames.txt
fi

# ==================================================================
#  PHASE 4: REPORT & SUMMARY
# ==================================================================
[[ "$QUIET" != true ]] && echo ""
log "${MAGENTA}${BOLD}═══ RESULTS SUMMARY ═══${NC}"
echo ""

TOTAL_SUBS=$(wc -l < "$ALL_SUBS" 2>/dev/null || echo 0)
TOTAL_RESOLVED=$(wc -l < "$RESOLVED" 2>/dev/null || echo 0)
TOTAL_LIVE=$(wc -l < "$LIVE_SUBS" 2>/dev/null || echo 0)
TOTAL_CNAMES=$(wc -l < "$CNAME_FILE" 2>/dev/null || echo 0)
TOTAL_AAAA=$(wc -l < "$RESOLVED_AAAA" 2>/dev/null || echo 0)
PORT_COUNT=0
[[ -f "$OUTDIR/ports.txt" ]] && PORT_COUNT=$(wc -l < "$OUTDIR/ports.txt" 2>/dev/null || echo 0)
SS_COUNT=0
ss_dir="$OUTDIR/screenshots"
[[ -d "$ss_dir" ]] && SS_COUNT=$(ls "$ss_dir"/*.png 2>/dev/null | wc -l || echo 0)
TOTAL_TAKEOVER=0
[[ -f "$TAKEOVER_FILE" ]] && TOTAL_TAKEOVER=$(wc -l < "$TAKEOVER_FILE" 2>/dev/null || echo 0)

log "  ${CYAN}Subdomains found:${NC}       $TOTAL_SUBS"
log "  ${CYAN}DNS resolved (A):${NC}       $TOTAL_RESOLVED"
log "  ${CYAN}DNS resolved (AAAA):${NC}    $TOTAL_AAAA"
log "  ${CYAN}Live (HTTP/S):${NC}          $TOTAL_LIVE"
log "  ${CYAN}CNAME records:${NC}          $TOTAL_CNAMES"
[[ -f "$OUTDIR/ports.txt" ]] && log "  ${CYAN}Open ports found:${NC}      $PORT_COUNT"
[[ -d "$ss_dir" ]] && log "  ${CYAN}Screenshots:${NC}           $SS_COUNT"

if [[ "$RESOLVE_ONLY" != true ]]; then
    if [[ "$TOTAL_TAKEOVER" -gt 0 ]]; then
        log "  ${RED}${BOLD}Takeover candidates:${NC}    ${RED}$TOTAL_TAKEOVER${NC}"
    else
        log "  ${GREEN}Takeover candidates:${NC}     0"
    fi
fi

# Zone Transfer Summary
if [[ -s "$OUTDIR/zone_transfer.txt" ]]; then
    ZT_COUNT=$(wc -l < "$OUTDIR/zone_transfer.txt")
    log "  ${RED}Zone transfer vulnerable:${NC} $ZT_COUNT nameservers"
fi

# Wildcard Summary
if [[ -f "$OUTDIR/wildcard_ip.txt" ]] && [[ -s "$OUTDIR/wildcard_ip.txt" ]]; then
    log "  ${YELLOW}Wildcard DNS detected:${NC}   Yes (see wildcard_ip.txt)"
fi

echo ""
log "${BOLD}Output directory:${NC} $OUTDIR"
echo ""
log "${BOLD}Key files:${NC}"
log "  all_subdomains.txt       — every subdomain discovered"
log "  resolved.txt             — subdomains with DNS A records (filtered)"
log "  resolved_aaaa.txt        — subdomains with DNS AAAA records"
log "  live_subdomains.txt      — subdomains responding to HTTP/S"
log "  cnames.txt               — CNAME records"
log "  httpx_full.txt           — HTTP details (status, title, tech)"
log "  ports.txt                — open ports (naabu top 100)"
[[ -d "$ss_dir" ]] && log "  screenshots/             — visual recon screenshots"
[[ -f "$OUTDIR/zone_transfer.txt" ]] && log "  zone_transfer.txt        — vulnerable nameservers"
[[ "$RESOLVE_ONLY" != true ]] && log "  takeover_vulnerable.txt  — potential takeover targets"
log "  subhunter.log            — full execution log"

# ---- Generate JSON Report ----
if command -v jq &>/dev/null; then
    JSON_REPORT="$OUTDIR/report.json"
    jq -n \
        --arg target "$DOMAIN" \
        --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
        --argjson subs "$TOTAL_SUBS" \
        --argjson resolved "$TOTAL_RESOLVED" \
        --argjson live "$TOTAL_LIVE" \
        --argjson cnames "$TOTAL_CNAMES" \
        --argjson takeovers "$TOTAL_TAKEOVER" \
        --argjson ports "$PORT_COUNT" \
        --argjson screenshots "$SS_COUNT" \
        '{target: $target, timestamp: $ts, stats: {total_subs: $subs, resolved: $resolved, live: $live, cnames: $cnames, takeovers: $takeovers, open_ports: $ports, screenshots: $screenshots}}' \
        > "$JSON_REPORT" 2>/dev/null || true

    if [[ -s "$TAKEOVER_FILE" ]]; then
        jq --arg takeovers "$(cat "$TAKEOVER_FILE")" '. + {takeover_details: $takeovers | split("\n")[:-1]}' \
            "$JSON_REPORT" > "$TMPDIR/report_tmp.$$.json" 2>/dev/null && \
            mv "$TMPDIR/report_tmp.$$.json" "$JSON_REPORT" 2>/dev/null || true
    fi

    log "${GREEN}[+] JSON report: $JSON_REPORT${NC}"
fi

echo ""
log "${GREEN}${BOLD}[*] SubHunter Pro v3.3 FINAL complete.${NC}"