#!/bin/bash

# ============================================
# RealiTLScanner 一键扫描脚本 v3.0 (HK服务器专用)
# 功能：自动检测环境、安装依赖、扫描、分析、推荐 TOP 10 最佳伪装域名（评分满分100）
# v3.0: 分析阶段增加动态进度条；结果以表格输出；
#       评分体系升级为满分100（签发机构+证书指纹+链长+热度综合）；
#       二次运行自动查漏补缺：对比历史记录，高亮新增/回归推荐并提示落榜域名
# v2.1: 优先下载预编译二进制（无需在目标机编译）；
#       扫描改为有界 CIDR（默认 /24，可传 /16），并支持目标足够时提前结束
# ============================================

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'

# 版本信息
SCRIPT_VERSION="3.0"

echo -e "${BLUE}╔═══════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║   RealiTLScanner 自动扫描工具 v${SCRIPT_VERSION}              ║${NC}"
echo -e "${BLUE}║   用于 VLESS+REALITY 伪装目标域名扫描                ║${NC}"
echo -e "${BLUE}║   评分满分100 · 二次运行自动查漏补缺                 ║${NC}"
echo -e "${BLUE}╚═══════════════════════════════════════════════════════╝${NC}"
echo -e "${CYAN}用法: bash realtls.sh [CIDR]   (默认 /16 范围大，/24 快速扫描)${NC}"
echo ""

# ============================================
# 函数定义
# ============================================

# 检测系统类型
detect_os() {
    if [[ -f /etc/debian_version ]]; then
        OS="debian"
        PKG_UPDATE="apt update -qq"
        PKG_INSTALL="apt install -y -qq"
    elif [[ -f /etc/redhat-release ]]; then
        OS="redhat"
        if command -v dnf &> /dev/null; then
            PKG_UPDATE="dnf check-update -q"
            PKG_INSTALL="dnf install -y -q"
        else
            PKG_UPDATE="yum check-update -q"
            PKG_INSTALL="yum install -y -q"
        fi
    else
        echo -e "${RED}⚠ 不支持的Linux发行版，请手动安装依赖${NC}"
        exit 1
    fi
    echo -e "${GREEN}✓ 检测到系统: $OS${NC}"
}

# 检查命令是否存在
check_command() {
    command -v "$1" &> /dev/null
}

# 获取本机公网IP
get_server_ip() {
    echo -e "${YELLOW}► [1/7] 获取本机公网IP...${NC}"
    SERVER_IP=$(curl -sf -4 --connect-timeout 5 ifconfig.me 2>/dev/null || \
                curl -sf -4 --connect-timeout 5 ipinfo.io/ip 2>/dev/null || \
                curl -sf -4 --connect-timeout 5 icanhazip.com 2>/dev/null || \
                curl -sf -4 --connect-timeout 5 ip.sb 2>/dev/null)
    
    if [ -z "$SERVER_IP" ] || [[ "$SERVER_IP" == *"html"* ]]; then
        echo -e "${RED}✗ 无法自动获取本机IP${NC}"
        read -p "请输入本机公网IP (按Enter跳过，将使用默认eth0 IP): " SERVER_IP
        if [ -z "$SERVER_IP" ]; then
            SERVER_IP=$(ip -4 addr show | grep -oE 'inet [0-9.]+' | awk '{print $2}' | grep -v '127.0.0.1' | head -1)
            if [ -z "$SERVER_IP" ]; then
                echo -e "${RED}✗ 无法获取IP，请手动指定${NC}"
                exit 1
            fi
            echo -e "${YELLOW}⚠ 使用内网IP: $SERVER_IP (可能影响扫描精度)${NC}"
        fi
    fi
    echo -e "${GREEN}✓ 本机IP: $SERVER_IP${NC}"
}

# 安装基础依赖
install_basic_deps() {
    echo -e "${YELLOW}► [2/7] 检查并安装基础依赖...${NC}"
    
    # 安装 bc (用于版本比较)
    if ! check_command bc; then
        echo -e "${YELLOW}⚠ 正在安装 bc...${NC}"
        $PKG_UPDATE
        $PKG_INSTALL bc
    fi
    
    # 安装 git
    if ! check_command git; then
        echo -e "${YELLOW}⚠ 正在安装 git...${NC}"
        $PKG_INSTALL git
    fi
    
    # 安装 wget 和 curl
    if ! check_command wget; then
        $PKG_INSTALL wget
    fi
    if ! check_command curl; then
        $PKG_INSTALL curl
    fi
    
    echo -e "${GREEN}✓ 基础依赖安装完成${NC}"
}

# 安装/升级 Go
install_go() {
    echo -e "${YELLOW}► [4/7] 检查 Go 环境...${NC}"
    
    GO_VERSION=""
    NEED_UPGRADE=false
    
    if check_command go; then
        GO_VERSION=$(go version | grep -oE 'go[0-9]+\.[0-9]+' | head -1 | sed 's/^go//')
        echo -e "  当前 Go 版本: $GO_VERSION"
        
        if [ -z "$GO_VERSION" ]; then
            NEED_UPGRADE=true
            echo -e "${YELLOW}⚠ 无法识别 Go 版本，将安装最新版${NC}"
        else
            # 版本比较 (需要 1.21+)
            GO_MAJOR=$(echo "$GO_VERSION" | cut -d. -f1)
            GO_MINOR=$(echo "$GO_VERSION" | cut -d. -f2)
            if [[ "$GO_MAJOR" -lt 1 ]] || [[ "$GO_MAJOR" -eq 1 && "$GO_MINOR" -lt 21 ]]; then
                NEED_UPGRADE=true
                echo -e "${YELLOW}⚠ Go 版本过低 ($GO_VERSION)，需要 1.21+${NC}"
            else
                echo -e "${GREEN}✓ Go 版本满足要求${NC}"
            fi
        fi
    else
        echo -e "${YELLOW}⚠ 未检测到 Go，将自动安装${NC}"
        NEED_UPGRADE=true
    fi
    
    if [ "$NEED_UPGRADE" = true ]; then
        echo -e "${YELLOW}正在获取 Go 最新稳定版本...${NC}"
        
        # 从 go.dev 获取最新稳定版本号 (如 go1.26.5)
        GO_LATEST=$(curl -sf --connect-timeout 10 "https://go.dev/dl/?mode=json" | grep -oE '"version":[[:space:]]*"go[0-9.]+"' | grep -oE 'go[0-9.]+' | grep -vE 'beta|rc' | head -1)
        
        if [ -z "$GO_LATEST" ]; then
            echo -e "${RED}✗ 无法获取 Go 最新版本号，请检查网络${NC}"
            exit 1
        fi
        
        # 检测架构
        ARCH=$(uname -m)
        case "$ARCH" in
            x86_64)  GO_ARCH="amd64" ;;
            aarch64) GO_ARCH="arm64" ;;
            *)       echo -e "${RED}✗ 不支持的架构: $ARCH${NC}"; exit 1 ;;
        esac
        
        echo -e "${YELLOW}正在安装/升级 Go $GO_LATEST ($GO_ARCH)...${NC}"
        
        GO_TARBALL="/tmp/${GO_LATEST}.linux-${GO_ARCH}.tar.gz"
        
        # 删除旧版
        rm -rf /usr/local/go
        
        # 下载并安装
        wget -q --show-progress "https://go.dev/dl/${GO_LATEST}.linux-${GO_ARCH}.tar.gz" -O "$GO_TARBALL"
        tar -C /usr/local -xzf "$GO_TARBALL"
        rm -f "$GO_TARBALL"
        
        # 设置环境变量
        export PATH=/usr/local/go/bin:$PATH
        
        # 写入 profile
        if ! grep -q '/usr/local/go/bin' ~/.bashrc; then
            echo 'export PATH=/usr/local/go/bin:$PATH' >> ~/.bashrc
        fi
        if ! grep -q '/usr/local/go/bin' ~/.profile 2>/dev/null; then
            echo 'export PATH=/usr/local/go/bin:$PATH' >> ~/.profile 2>/dev/null || true
        fi
        
        # 验证安装
        export PATH=/usr/local/go/bin:$PATH
        GO_VERSION=$(go version | grep -oE 'go[0-9]+\.[0-9]+' | head -1 | sed 's/^go//')
        echo -e "${GREEN}✓ Go 安装完成: $(go version)${NC}"
    fi
    
    # 设置 GOPROXY (加速下载)
    export GOPROXY=https://goproxy.io,direct
    echo -e "${GREEN}✓ Go 环境准备完成${NC}"
}

# 优先下载预编译二进制（镜像 → GitHub Release），避免在目标机安装 Go 并编译
fetch_scanner_binary() {
    echo -e "${YELLOW}► [3/7] 获取 RealiTLScanner 预编译二进制...${NC}"
    
    local arch
    arch=$(uname -m)
    case "$arch" in
        x86_64)  BIN_ARCH="amd64" ;;
        aarch64) BIN_ARCH="arm64" ;;
        *)       echo -e "${YELLOW}⚠ 无 ${arch} 预编译包，将走源码编译${NC}"
                 return 1 ;;
    esac
    
    mkdir -p /tmp/RealiTLScanner
    local urls=(
        "https://ipan.mbvpn.cn/realtls/RealiTLScanner-linux-${BIN_ARCH}"
        "https://github.com/XTLS/RealiTLScanner/releases/download/v0.2.3/RealiTLScanner-linux-${BIN_ARCH}"
    )
    
    for u in "${urls[@]}"; do
        echo -e "  正在下载: $u"
        if curl -sfL --connect-timeout 8 -m 120 -o /tmp/RealiTLScanner/RealiTLScanner "$u"; then
            chmod +x /tmp/RealiTLScanner/RealiTLScanner
            echo -e "${GREEN}✓ 预编译扫描器获取成功${NC}"
            return 0
        fi
        echo -e "${YELLOW}  ✗ 下载失败，尝试下一个源...${NC}"
    done
    
    echo -e "${YELLOW}⚠ 预编译二进制下载失败，回退源码编译${NC}"
    return 1
}

# 源码编译（仅预编译下载失败时兜底）
build_scanner() {
    echo -e "${YELLOW}► [4/7] 下载源码并编译 RealiTLScanner...${NC}"
    
    cd /tmp
    rm -rf RealiTLScanner
    mkdir -p RealiTLScanner
    
    echo -e "  正在克隆仓库..."
    if ! git clone --depth 1 https://github.com/XTLS/RealiTLScanner.git /tmp/RealiTLScanner; then
        echo -e "${RED}✗ 仓库克隆失败，无法编译${NC}"
        exit 1
    fi
    
    cd /tmp/RealiTLScanner
    
    echo -e "  正在下载依赖..."
    go mod download -x 2>&1 | tail -5
    
    echo -e "  正在编译..."
    go build -o RealiTLScanner
    
    if [ ! -f "./RealiTLScanner" ]; then
        echo -e "${RED}✗ 编译失败！${NC}"
        echo -e "${YELLOW}提示: 可能是网络问题，尝试使用代理或手动编译${NC}"
        exit 1
    fi
    
    echo -e "${GREEN}✓ 编译成功！${NC}"
}

# 执行扫描（有界 CIDR，避免无限模式跑不完；目标足够时提前结束）
run_scan() {
    echo -e "${YELLOW}► [5/7] 开始扫描附近网站...${NC}"
    
    # 扫描范围：默认 /16（范围大、目标多，目标足够时自动提前结束）；
    # 想快速扫一下可传 /24（如 bash realtls.sh /24）
    SCAN_CIDR="${1:-/16}"
    [[ "$SCAN_CIDR" =~ ^/[0-9]{1,2}$ ]] || SCAN_CIDR="/16"
    case "$SCAN_CIDR" in
        /24) THREAD=100;  MAX_WAIT=900;  ETA="1-3 分钟" ;;
        /16) THREAD=300;  MAX_WAIT=3600; ETA="5-20 分钟（目标足够时自动提前结束）" ;;
        *)   THREAD=200;  MAX_WAIT=3600; ETA="视范围而定" ;;
    esac
    
    echo -e "  目标: ${SERVER_IP}${SCAN_CIDR}"
    echo -e "  端口: 443"
    echo -e "  线程: ${THREAD}"
    echo -e "  超时: 5s"
    echo -e "${CYAN}  此过程可能需要 ${ETA}，请耐心等待...${NC}"
    echo ""
    
    cd /tmp/RealiTLScanner
    
    # 计算扫描 IP 总量（用于真实进度百分比）：/16=65536, /24=256, ...
    CIDR_PREFIX="${SCAN_CIDR#/}"
    IP_TOTAL=$((2 ** (32 - CIDR_PREFIX)))

    # 后台执行扫描（-v 开启 verbose：每扫描一个 IP 记一行日志，用于统计真实进度），
    # 输出重定向到日志
    ./RealiTLScanner -addr "${SERVER_IP}${SCAN_CIDR}" -port 443 -thread "$THREAD" -timeout 5 -v -out /tmp/scan_result.csv > /tmp/scan_log.txt 2>&1 &
    SCAN_PID=$!

    # 动态进度条（拉取进度 = 已扫描 IP 数 / 范围总 IP 数）
    LAST_DOMAIN=""
    LAST_IP=""
    START_TIME=$(date +%s)
    FOUND=0
    LAST_FOUND=0
    IDLE_TICKS=0
    TICK=0
    SCANNED=0

    while kill -0 "$SCAN_PID" 2>/dev/null; do
        TICK=$((TICK + 1))
        ELAPSED=$(( $(date +%s) - START_TIME ))

        # 每 10 个 tick（约1秒）读取一次日志，避免频繁 grep 大文件拖慢扫描
        if [ $((TICK % 10)) -eq 1 ]; then
            # 已扫描 IP ≈ 日志行数-1（verbose 模式每个 IP 恰好一行：
            #   Cannot dial / handshake failed / Connected to target）
            SCANNED=$(($(wc -l < /tmp/scan_log.txt 2>/dev/null || echo 0) - 1))
            [ "$SCANNED" -lt 0 ] && SCANNED=0
            # 已发现可行目标
            FOUND=$(grep -c "feasible=true" /tmp/scan_log.txt 2>/dev/null || true)
            # 最新扫描到的 IP 与最新证书域名（实时反馈「正在读取」）
            LAST_IP=$(grep -oE '(target|ip)=[0-9.]+' /tmp/scan_log.txt 2>/dev/null | sed 's/.*=//' | tail -1)
            LAST_DOMAIN=$(grep -oE 'cert-domain=[^ ]*' /tmp/scan_log.txt 2>/dev/null | sed 's/.*=//' | tail -1 | tr -d '"')
        fi

        # 记录是否有新目标出现（用于提前结束判断）
        if [[ "$FOUND" -gt "$LAST_FOUND" ]]; then
            LAST_FOUND="$FOUND"
            IDLE_TICKS=0
        else
            IDLE_TICKS=$((IDLE_TICKS + 1))
        fi

        # 真实扫描进度
        if [ "$SCANNED" -ge "$IP_TOTAL" ]; then PCT=100; else PCT=$((SCANNED * 100 / IP_TOTAL)); fi
        [ "$PCT" -gt 100 ] && PCT=100
        FILLED=$((PCT * 40 / 100))
        BAR=""
        for ((_i=0; _i<40; _i++)); do
            if [ "$_i" -lt "$FILLED" ]; then BAR+="█"; else BAR+="░"; fi
        done

        # 预估剩余时间 = 剩余IP / 平均扫描速率
        RATE=0
        [ "$ELAPSED" -gt 0 ] && RATE=$((SCANNED / ELAPSED))
        if [ "$RATE" -gt 0 ] && [ "$SCANNED" -lt "$IP_TOTAL" ]; then
            REMAIN=$(((IP_TOTAL - SCANNED) / RATE))
            ETA_STR="剩余 $(printf "%02d:%02d:%02d" $((REMAIN / 3600)) $(((REMAIN % 3600) / 60)) $((REMAIN % 60)))"
        else
            ETA_STR="剩余 计算中..."
        fi
        HMS="$(printf "%02d" $((ELAPSED / 3600))):$(printf "%02d" $(((ELAPSED % 3600) / 60))):$(printf "%02d" $((ELAPSED % 60)))"

        printf "\r  ${CYAN}%3d%%${NC} ${GREEN}%s${NC} 扫描: ${YELLOW}%-6s${NC}/${IP_TOTAL} 发现: ${GREEN}%-4s${NC} 当前IP: ${CYAN}%-15s${NC} ${CYAN}%-20s${NC} 用时: %s ${BLUE}%s${NC}   " \
            "$PCT" "$BAR" "$SCANNED" "$FOUND" "${LAST_IP:-...}" "${LAST_DOMAIN:-}" "$HMS" "$ETA_STR"

        # 目标足够(≥150)且 60 秒无新增 → 提前结束，不再等全部扫完
        if [[ "$FOUND" -ge 150 ]] && [[ "$IDLE_TICKS" -ge 600 ]]; then
            echo ""
            echo -e "${GREEN}✓ 已发现 ${FOUND} 个目标且 60 秒无新增，提前结束扫描${NC}"
            kill "$SCAN_PID" 2>/dev/null
            break
        fi
        
        if [ "$ELAPSED" -ge "$MAX_WAIT" ]; then
            echo ""
            echo -e "${RED}✗ 扫描超时(${MAX_WAIT}s)，强制结束${NC}"
            kill "$SCAN_PID" 2>/dev/null
            break
        fi
        sleep 0.1
    done
    wait "$SCAN_PID" 2>/dev/null
    printf "\r%-80s\r" ""
    
    if [ ! -f "/tmp/scan_result.csv" ] || [ ! -s "/tmp/scan_result.csv" ]; then
        echo -e "${RED}✗ 扫描失败，未生成结果文件！${NC}"
        echo -e "${YELLOW}查看日志: /tmp/scan_log.txt${NC}"
        exit 1
    fi
    
    # 统计结果
    SCAN_COUNT=$(wc -l < /tmp/scan_result.csv)
    if [ "$SCAN_COUNT" -le 1 ]; then
        printf "\r%-80s\r" ""
        echo -e "${RED}✗ 未扫描到任何目标！${NC}"
        echo -e "${YELLOW}可能原因: 防火墙限制、IP不正确、扫描范围内站点过少${NC}"
        echo -e "${YELLOW}尝试: 确认使用 /16 范围，或检查防火墙对 443 出站限制${NC}"
        exit 1
    fi
    
    echo -e "${GREEN}✓ 扫描完成！共发现 $((SCAN_COUNT - 1)) 个候选目标${NC}"
    if [ "$SCAN_COUNT" -le 6 ]; then
        echo -e "${YELLOW}提示: 候选目标较少，可执行 bash realtls.sh /16 扩大范围后获得更多选择${NC}"
    fi
}

# 分析结果并推荐（动态进度条 + 满分100评分体系）
analyze_results() {
    echo -e "${YELLOW}► [6/7] 分析扫描结果，推荐最佳伪装域名...${NC}"

    local total count step pct last_pct filled i
    local line ip origin tls alpn clen sig pubkey domain issuer geo rest dom lowerdom lowerissuer
    local score skip b bar

    total=$(wc -l < /tmp/scan_result.csv)
    total=$((total - 1))   # 去掉表头
    if [ "$total" -le 0 ]; then
        echo -e "${RED}✗ 无有效数据行，无法分析${NC}"
        exit 1
    fi

    # 进度步进：<=200 行逐行刷新；更多行按约 1% 步进，保证进度条可见又不过慢
    step=1
    if [ "$total" -gt 200 ]; then step=$((total / 100)); fi
    echo -e "  共 ${GREEN}${total}${NC} 行待分析，评分满分 ${GREEN}100${NC} 分，请稍候..."
    echo ""

    # 结果写 stdout 重定向到文件；进度条走 stderr，不污染结果文件
    {
        tail -n +2 /tmp/scan_result.csv | while IFS= read -r line || [ -n "$line" ]; do
            count=$((count + 1))

            # RealiTLScanner 输出格式(CSV): IP,ORIGIN,TLS,ALPN,CURVE,LENGTH,SIG,KEY,DOMAIN,"ISSUER",GEO
            # 仅 ISSUER 字段带引号且可能含逗号，用 rest 截取还原
            IFS=',' read -r ip origin tls alpn curve clen sig pubkey domain rest <<< "$line"
            issuer="${rest#\"}"; issuer="${issuer%%\",*}"
            geo="${rest##*\",}"; geo="${geo%\"}"

            # 去掉证书域名通配符前缀，如 *.example.com -> example.com
            dom="${domain#\*.}"
            [ -z "$dom" ] && dom="$origin"
            [ -z "$dom" ] && continue

            # 过滤：纯 IP 域名、含空格/证书模板的伪域名
            [[ "$dom" =~ ^[0-9.]+$ ]] && continue
            case "$dom" in *[[:space:]]*|*Certificate*) continue ;; esac

            # 黑名单域名（子串匹配，不区分大小写）
            lowerdom="${dom,,}"
            skip=0
            for b in microsoft.com cloudflare.com akamai.net fastly.net azure.com aws.amazon.com; do
                if [[ "$lowerdom" == *"$b"* ]]; then skip=1; break; fi
            done
            [ "$skip" -eq 1 ] && continue

            # ===== 评分（满分 100）=====
            score=20
            lowerissuer="${issuer,,}"
            # 签发机构信任度
            if [[ "$lowerissuer" =~ let.?s.?encrypt|zerossl ]]; then score=$((score + 50))
            elif [[ "$lowerissuer" =~ sectigo|digicert|globalsign|google.?trust|quovadis ]]; then score=$((score + 40))
            elif [[ "$lowerissuer" =~ amazon|entrust|geotrust|rapidssl|trustasia|comodo|symantec|actalis|ssl.com|buypass|godaddy|certum|gandi ]]; then score=$((score + 30))
            elif [[ "$lowerissuer" =~ cloudflare ]]; then score=$((score + 15))
            fi
            # 证书公钥：ECDSA 更贴近 REALITY 指纹习惯
            case "${pubkey,,}" in
                ecdsa) score=$((score + 10)) ;;
                rsa)   score=$((score + 5)) ;;
            esac
            # 签名算法强度
            case "${sig,,}" in
                *ecdsa*sha256*|*sha256*rsa*) score=$((score + 5)) ;;
            esac
            # TLS 1.3 / h2 ALPN / 证书链>=2
            [[ "$tls" == *1.3* ]] && score=$((score + 5))
            [[ "$alpn" == *h2* ]] && score=$((score + 5))
            case "$clen" in *"certs count: 2"*) score=$((score + 5)) ;; esac

            # 大厂热门域名降权（REALITY 撞车/易被封锁）
            if [[ "$lowerdom" =~ google|youtube|facebook|twitter|github|amazon|netflix|apple|microsoft|cloudflare|akamai|azure|fastly|alicdn|cloudfront|cdn ]]; then
                score=$((score - 30))
            fi
            # 纯数字开头等泛解析风域名降权
            [[ "$lowerdom" =~ ^[0-9] ]] && score=$((score - 5))

            [ "$score" -gt 100 ] && score=100
            [ "$score" -lt 0 ] && score=0

            printf '%s,%s,%s,%s,%s\n' "$score" "$dom" "$ip" "$issuer" "$geo"

            # ===== 动态进度条（stderr，不污染结果文件）=====
            pct=$((count * 100 / total))
            [ "$pct" -gt 100 ] && pct=100
            if [ "$pct" != "$last_pct" ] && { [ $((count % step)) -eq 0 ] || [ "$count" -eq "$total" ]; }; then
                last_pct=$pct
                filled=$((pct * 40 / 100))
                bar=""
                for ((i = 0; i < 40; i++)); do
                    if [ "$i" -lt "$filled" ]; then bar+="█"; else bar+="░"; fi
                done
                printf "\r  ${CYAN}%3d%%${NC} ${GREEN}%s${NC} ${YELLOW}%-38s${NC} 评分: ${BLUE}%3d${NC}/100  %s   " \
                    "$pct" "$bar" "$dom" "$score" "$(date +%H:%M:%S)" >&2
                sleep 0.015
            fi
        done
    } > /tmp/scored_domains.txt
    printf "\r%-90s\r" "" >&2

    if [ ! -s /tmp/scored_domains.txt ]; then
        echo -e "${RED}✗ 未找到符合条件的域名${NC}"
        echo -e "${YELLOW}建议: 检查扫描结果，或放宽过滤条件${NC}"
        echo -e "${YELLOW}查看完整结果: cat /tmp/scan_result.csv${NC}"
        exit 1
    fi

    echo -e "${GREEN}✓ 分析完成（处理 ${total} 行，通过过滤并评分 $(wc -l < /tmp/scored_domains.txt) 条）${NC}"

    # 按评分排序，按域名去重，取前10 (文件全为数字开头数据行)
    sort -t',' -k1,1nr /tmp/scored_domains.txt | awk -F',' '!seen[tolower($2)]++' | head -10 > /tmp/top_domains.txt

    # 生成推荐列表（带表头，签发机构加引号防止逗号破坏 CSV）
    echo '排名,域名,IP,签发机构,评分,地区' > /tmp/recommended_domains.csv
    local rank=0
    # scored 行格式: score,domain,ip,issuer,geo（issuer 可能含逗号，取首尾字段还原）
    while IFS=',' read -r score domain ip rest; do
        rank=$((rank + 1))
        issuer="${rest%,*}"; geo="${rest##*,}"
        printf '%s,%s,%s,"%s",%s,%s\n' "$rank" "$domain" "$ip" "$issuer" "$score" "$geo" >> /tmp/recommended_domains.csv
    done < /tmp/top_domains.txt

    echo -e "${GREEN}✓ 已生成 TOP $rank 推荐列表${NC}"
}

# ============================================
# 历史记录：二次运行查漏补缺
# ============================================

# 加载历史记录（上一次运行的 TOP10 与累计推荐域名）
load_history() {
    PREV_DOMAINS=""
    PREV_DATE=""
    HIST_COUNT=0
    if [ -s /root/.realtls_history ]; then
        HIST_COUNT=$(wc -l < /root/.realtls_history)
        PREV_DATE=$(tail -1 /root/.realtls_history | cut -d' ' -f1,2)
        PREV_DOMAINS=$(tail -1 /root/.realtls_history | sed 's/^.*top10: //')
    fi
}

# 保存本次运行结果到历史记录（历史行 + 累计已知域名库）
save_history() {
    # $1 = 本次 TOP10 域名（逗号分隔）
    printf '%s top10: %s\n' "$(date '+%Y-%m-%d %H:%M')" "$1" >> /root/.realtls_history
    local d
    IFS=',' read -ra __arr <<< "$1"
    for d in "${__arr[@]}"; do
        grep -qxF "$d" /root/.realtls_known 2>/dev/null || printf '%s\n' "$d" >> /root/.realtls_known
    done
}

# 表格分隔线
mk_sep() {   # $1=左边 $2=填充 $3=连接 $4=右边
    local out="$1" seg w
    local -a W=(2 5 36 14 22 8)
    for w in "${W[@]}"; do
        printf -v seg '%*s' $((w + 2)) ''
        out+="${seg// /$2}${3}"
    done
    out="${out%$3}$4"
    printf '%s\n' "$out"
}

# 彩色定宽单元格（先填充后上色，保证对齐）
cell() {     # $1=宽度 $2=文本 $3=颜色
    local padded
    printf -v padded '%-*s' "$1" "$2"
    printf "%b%s%b" "$3" "$padded" "$NC"
}

# 显示推荐结果（表格 + 查漏补缺）
show_results() {
    echo -e "${YELLOW}► [7/7] 推荐结果${NC}"
    echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
    echo -e "${BLUE}║  🎯 最佳伪装域名 TOP 10 (评分满分 100)                    ║${NC}"
    echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
    echo ""

    load_history

    # 当前 TOP10 域名列表
    local -a CUR=()
    local d
    while IFS= read -r d; do [ -n "$d" ] && CUR+=("$d"); done < <(cut -d, -f2 /tmp/top_domains.txt)

    # 上次 TOP10 域名列表
    local -a PREV=()
    IFS=',' read -ra PREV <<< "$PREV_DOMAINS"

    local rank=0 score domain ip issuer geo rest note
    local new_count=0 ret_count=0 re_count=0

    # 表头与分隔线
    local SEP_TOP SEP_MID SEP_BOT
    SEP_TOP=$(mk_sep '┌' '─' '┬' '┐')
    SEP_MID=$(mk_sep '├' '─' '┼' '┤')
    SEP_BOT=$(mk_sep '└' '─' '┴' '┘')

    printf "%b\n" "$SEP_TOP"
    printf "│ %-2s │ %-5s │ %-36s │ %-14s │ %-22s │ %-8s │\n" "No" "评分" "域名" "IP" "签发机构" "状态"
    printf "%b\n" "$SEP_MID"

    while IFS=',' read -r score domain ip rest; do
        rank=$((rank + 1))
        issuer="${rest%,*}"; geo="${rest##*,}"

        # 查漏补缺：标记新增/保留/回归（用完整域名判断，截断仅用于显示）
        note="KEEP"
        if ! grep -qxF "$domain" /root/.realtls_known 2>/dev/null; then
            note="NEW";  new_count=$((new_count + 1))
        else
            local in_prev=0 p
            for p in "${PREV[@]}"; do [ "$p" = "$domain" ] && in_prev=1 && break; done
            if [ "$in_prev" -eq 1 ]; then note="KEEP"; ret_count=$((ret_count + 1)); else note="BACK"; re_count=$((re_count + 1)); fi
        fi

        [ "${#domain}" -gt 36 ] && domain="${domain:0:35}…"
        [ "${#issuer}" -gt 22 ] && issuer="${issuer:0:21}…"

        if [ "$score" -ge 90 ]; then SCORE_COLOR="$GREEN"; else SCORE_COLOR="$YELLOW"; fi

        printf "│ %s │ %s │ %s │ %s │ %s │ %s │\n" \
            "$(cell 2 "$rank" "$GREEN")" \
            "$(cell 5 "$score" "$SCORE_COLOR")" \
            "$(cell 36 "$domain" "$CYAN")" \
            "$(cell 14 "$ip" "$NC")" \
            "$(cell 22 "$issuer" "$YELLOW")" \
            "$(cell 8 "$note" "$GREEN")"
    done < /tmp/top_domains.txt

    printf "%b\n" "$SEP_BOT"
    echo ""
    echo -e "${GREEN}📁 完整扫描结果: /tmp/scan_result.csv"
    echo -e "📁 推荐列表: /tmp/recommended_domains.csv"
    echo -e "📁 扫描日志: /tmp/scan_log.txt${NC}"

    # ===== 查漏补缺（对比上次运行）=====
    echo ""
    echo -e "${BLUE}══════════════ 查漏补缺 (对比上次运行) ══════════════${NC}"
    echo -e "  ${GREEN}NEW${NC}=历史首次推荐  ${GREEN}KEEP${NC}=上次保留  ${GREEN}BACK${NC}=历史回归  ${GREEN}DROP${NC}=上轮落榜"

    if [ "$HIST_COUNT" -le 0 ]; then
        echo -e "${CYAN}  ℹ 首次运行，无历史对比。本次 TOP10 已记录为下次运行的基准。${NC}"
    else
        # 本次新增（历史从未推荐）
        local -a new_domains=()
        while IFS=',' read -r score domain ip rest; do
            if ! grep -qxF "$domain" /root/.realtls_known 2>/dev/null; then new_domains+=("${domain}"); fi
        done < /tmp/top_domains.txt
        if [ "${#new_domains[@]}" -gt 0 ]; then
            echo -e "  ${GREEN}🆕 本次新增推荐 (${#new_domains[@]} 个):${NC} ${CYAN}${new_domains[*]}${NC}"
        else
            echo -e "  ${GREEN}🆕 本次新增推荐:${NC} 无（都在历史库中）"
        fi

        # 上轮上榜本次落榜
        local -a dropped=()
        local found=0 p dd
        for p in "${PREV[@]}"; do
            [ -z "$p" ] && continue
            found=0
            for dd in "${CUR[@]}"; do [ "$dd" = "$p" ] && found=1 && break; done
            [ "$found" -eq 0 ] && dropped+=("$p")
        done
        if [ "${#dropped[@]}" -gt 0 ]; then
            echo -e "  ${YELLOW}📉 上轮上榜本次落榜 (${#dropped[@]} 个):${NC} ${CYAN}${dropped[*]}${NC}"
            echo -e "  ${YELLOW}  ↳ 说明: 落榜域名可能已失效/被过滤，建议以本次为准重新配置${NC}"
        else
            echo -e "  ${GREEN}📉 上轮上榜本次落榜:${NC} 无（TOP10 全部保留）"
        fi
        echo -e "  ${BLUE}ℹ 上次运行: ${PREV_DATE:-未知} · 共 ${HIST_COUNT} 次历史记录${NC}"
    fi

    # 保存本次结果为下次对比基准
    save_history "$(IFS=,; echo "${CUR[*]}")"
}

# 清理临时文件
cleanup() {
    echo -e "${YELLOW}是否清理临时文件? (y/n): ${NC}"
    read -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        rm -f /tmp/go*.linux-*.tar.gz
        rm -f /tmp/scored_domains.txt /tmp/top_domains.txt
        rm -f /tmp/scan_log.txt /tmp/reality_config.txt
        echo -e "${GREEN}✓ 清理完成${NC}"
    fi
}

# 导出配置建议
export_config() {
    echo -e "${YELLOW}是否导出推荐域名到配置文件? (y/n): ${NC}"
    read -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        echo "# ============================================" > /tmp/reality_config.txt
        echo "# REALITY 伪装域名推荐配置 (生成于 $(date))" >> /tmp/reality_config.txt
        echo "# ============================================" >> /tmp/reality_config.txt
        echo "" >> /tmp/reality_config.txt
        
        # 格式: 排名,域名,IP,"签发机构",评分,地区（签发机构可能含逗号，用引号包裹）
        tail -n +2 /tmp/recommended_domains.csv | while IFS=',' read -r rank domain ip rest; do
            issuer="${rest#\"}"; issuer="${issuer%%\",*}"
            score="${rest#*\",}"; score="${score%%,*}"
            echo "# ${rank}. $domain" >> /tmp/reality_config.txt
            echo "目标域名: $domain" >> /tmp/reality_config.txt
            echo "  IP: $ip" >> /tmp/reality_config.txt
            echo "  评分: $score" >> /tmp/reality_config.txt
            echo "  签发机构: $issuer" >> /tmp/reality_config.txt
            echo "  服务端配置: \"dest\": \"${domain}:443\"" >> /tmp/reality_config.txt
            echo "  客户端配置: \"serverName\": \"${domain}\"" >> /tmp/reality_config.txt
            echo "" >> /tmp/reality_config.txt
        done
        
        echo -e "${GREEN}✓ 配置已导出到: /tmp/reality_config.txt${NC}"
        cat /tmp/reality_config.txt
    fi
}

# ============================================
# 主程序
# ============================================

main() {
    # 检测系统
    detect_os
    
    # 获取IP
    get_server_ip
    
    # 安装基础依赖
    install_basic_deps
    
    # 优先下载预编译二进制；失败才安装 Go 并源码编译
    if ! fetch_scanner_binary; then
        install_go
        build_scanner
    fi
    
    # 执行扫描（默认 /24，可通过参数扩大范围）
    run_scan "$1"
    
    # 分析结果
    analyze_results
    
    # 显示结果
    show_results
    
    # 导出配置
    export_config
    
    # 清理
    cleanup
    
    echo -e "${GREEN}╔═══════════════════════════════════════════════════════╗${NC}"
    echo -e "${GREEN}║  ✅ 所有步骤完成！                                   ║${NC}"
    echo -e "${GREEN}║  请将推荐域名填入 3x-ui 的 dest 和 serverNames 字段  ║${NC}"
    echo -e "${GREEN}╚═══════════════════════════════════════════════════════╝${NC}"
}

# 执行主程序
main "$@"