#!/usr/bin/env bash
#
# cloud-proxy-setup.sh — 云机隐藏代理 + 普通反向代理（多系统可移植统一修复版）
#
set -euo pipefail

# ======================== 路径与常量 ========================
NGINX_CONF="/etc/nginx/nginx.conf"
CLOUD_CONF="/etc/nginx/conf.d/cloud_phone_proxy.conf"
CLOUD_META="/etc/nginx/conf.d/cloud_phone_proxy.meta"
CLOUD_NOTES="/etc/nginx/conf.d/cloud_phone_proxy.notes"
WRAP_DIR="/var/www/proxy-wrap"
GENERIC_CONF="/etc/nginx/conf.d/vps_proxy.conf"
GENERIC_META="/etc/nginx/conf.d/vps_proxy.meta"
SQUID_PORT="9678"
DEFAULT_SITE="/etc/nginx/sites-enabled/default"
DEFAULT_SITE_BAK="/etc/nginx/sites-enabled/default.bak.cloudproxy"
DEFAULT_CLOUD_TARGET="console.chinac.com"

if [ -t 1 ]; then
    C='\033[1;36m'; G='\033[1;32m'; Y='\033[1;33m'; R='\033[1;31m'; N='\033[0m'
else
    C=''; G=''; Y=''; R=''; N=''
fi
[ -t 0 ] && stty erase '^H' 2>/dev/null || true

# ======================== 基础工具 ========================
die() { echo -e "${R}[错误] $*${N}" >&2; exit 1; }
ok() { echo -e "${G}[成功] $*${N}"; }
info() { echo -e "${C}[信息] $*${N}"; }
warn() { echo -e "${Y}[提示] $*${N}"; }

pause() {
    echo ""
    printf "%b" "${G}按回车返回...${N}"
    read -r _ || true
}

ask() {
    local prompt="$1" result
    printf "%b" "$prompt" >&2
    read -r result || true
    printf '%s' "$result"
}

check_root() {
    [ "$(id -u)" -eq 0 ] || die "请使用 root 运行: sudo bash $0"
}

detect_os() {
    if [ -f /etc/os-release ]; then
        # shellcheck disable=SC1090
        . /etc/os-release
        OS_ID="${ID:-unknown}"
    elif [ -f /etc/redhat-release ]; then
        OS_ID="centos"
    else
        OS_ID="unknown"
    fi
    case "${OS_ID}" in
        ubuntu|debian|linuxmint|kali|raspbian) PKG=apt ;;
        centos|rhel|rocky|almalinux|fedora|alinux|anolis|opencloudos|tencentos|ctyunos|amzn)
            if command -v dnf >/dev/null 2>&1; then PKG=dnf; else PKG=yum; fi
            ;;
        *)
            if command -v apt-get >/dev/null 2>&1; then PKG=apt
            elif command -v dnf >/dev/null 2>&1; then PKG=dnf
            elif command -v yum >/dev/null 2>&1; then PKG=yum
            else die "不支持的系统，未找到 apt/yum/dnf"
            fi
            ;;
    esac
}

pkg_install() {
    local pkgs=("$@")
    case "$PKG" in
        apt)
            export DEBIAN_FRONTEND=noninteractive
            apt-get install -f -y >/dev/null 2>&1 || true
            apt-get update -y >/dev/null 2>&1 || true
            apt-get install -y "${pkgs[@]}"
            ;;
        dnf)
            dnf install -y epel-release >/dev/null 2>&1 || true
            dnf install -y "${pkgs[@]}"
            ;;
        yum)
            yum install -y epel-release >/dev/null 2>&1 || true
            yum install -y "${pkgs[@]}"
            ;;
    esac
}

get_public_ip() {
    local ip candidate
    for candidate in \
        "https://api.ipify.org" \
        "https://ipv4.icanhazip.com" \
        "https://ifconfig.me/ip" \
        "http://ip.sb"
    do
        ip=$(curl -4 -fsS --connect-timeout 3 --max-time 6 "$candidate" 2>/dev/null | tr -d '[:space:]' || true)
        [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && { echo "$ip"; return 0; }
    done
    echo ""
}

clean_host() {
    local raw="$1"
    echo "$raw" | sed 's/#.*//' | sed -e 's|^https\?://||' -e 's|/.*$||' -e 's|:.*$||' | tr -d '[:space:]'
}

open_port() {
    local port="$1"
    if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld 2>/dev/null; then
        firewall-cmd --permanent --add-port="${port}/tcp" >/dev/null 2>&1 || true
        firewall-cmd --reload >/dev/null 2>&1 || true
    fi
    if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -qi active; then
        ufw allow "${port}/tcp" >/dev/null 2>&1 || true
    fi
    if command -v iptables >/dev/null 2>&1; then
        iptables -C INPUT -p tcp --dport "${port}" -j ACCEPT 2>/dev/null \
            || iptables -I INPUT -p tcp --dport "${port}" -j ACCEPT 2>/dev/null || true
    fi
}

# 🛠️ 修复：安全注释 IPv6 监听，防止误删整行破坏语法
strip_ipv6_listen() {
    local f
    while IFS= read -r f; do
        [ -n "$f" ] || continue
        # 将 listen [::]:xx 替换为注释，而非直接删除整行
        sed -i.bak.cloudproxy 's/^[[:space:]]*listen[[:space:]]*\[::\]/# &/' "$f" 2>/dev/null || true
        rm -f "${f}.bak.cloudproxy"
    done < <(find /etc/nginx -type f \( -name '*.conf' -o -name 'default' \) 2>/dev/null || true)
}

# 🛠️ 修复：增加防重复插入校验
ensure_websocket_map() {
    [ -f "$NGINX_CONF" ] || return 0
    # 全局检查，只要任意配置文件中有 $connection_upgrade 变量映射即跳过
    if grep -rq 'connection_upgrade' /etc/nginx/ 2>/dev/null; then
        return 0
    fi
    if ! grep -qE '^[[:space:]]*http[[:space:]]*\{' "$NGINX_CONF" 2>/dev/null; then
        warn "未找到 http{} 块，跳过 websocket map（请手动配置）"
        return 0
    fi
    awk '
        BEGIN { done=0 }
        /^[[:space:]]*http[[:space:]]*\{/ && !done {
            print
            print "    map $http_upgrade $connection_upgrade {"
            print "        default upgrade;"
            print "        '\'''\''      close;"
            print "    }"
            done=1
            next
        }
        { print }
    ' "$NGINX_CONF" > "${NGINX_CONF}.tmp.cloudproxy" \
        && mv -f "${NGINX_CONF}.tmp.cloudproxy" "$NGINX_CONF"
}

ensure_sub_module() {
    if nginx -V 2>&1 | grep -q 'http_sub_module'; then
        return 0
    fi
    case "$PKG" in
        dnf|yum)
            info "尝试安装 nginx sub 模块 ..."
            pkg_install nginx-mod-http-sub 2>/dev/null || pkg_install nginx-module-sub 2>/dev/null || true
            ;;
    esac
    if ! nginx -V 2>&1 | grep -q 'http_sub_module'; then
        warn "当前 Nginx 可能缺少 sub_filter 模块，云手机链接替换效果会变差"
    fi
}

disable_default_site() {
    if [ -e "$DEFAULT_SITE" ] && [ ! -e "$DEFAULT_SITE_BAK" ]; then
        mv "$DEFAULT_SITE" "$DEFAULT_SITE_BAK"
        warn "已停用默认站点 $DEFAULT_SITE"
    fi
    if [ -f /etc/nginx/conf.d/default.conf ] && [ ! -f /etc/nginx/conf.d/default.conf.bak.cloudproxy ]; then
        mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak.cloudproxy
        warn "已停用 /etc/nginx/conf.d/default.conf"
    fi
}

restore_default_site() {
    [ -e "$DEFAULT_SITE_BAK" ] && [ ! -e "$DEFAULT_SITE" ] && mv "$DEFAULT_SITE_BAK" "$DEFAULT_SITE" || true
    [ -f /etc/nginx/conf.d/default.conf.bak.cloudproxy ] && [ ! -f /etc/nginx/conf.d/default.conf ] \
        && mv /etc/nginx/conf.d/default.conf.bak.cloudproxy /etc/nginx/conf.d/default.conf || true
}

detect_ssl_cert() {
    local domain="$1"
    local pairs=(
        "/etc/letsencrypt/live/${domain}/fullchain.pem|/etc/letsencrypt/live/${domain}/privkey.pem"
        "/home/web/certs/${domain}_cert.pem|/home/web/certs/${domain}_key.pem"
        "/etc/nginx/ssl/${domain}.crt|/etc/nginx/ssl/${domain}.key"
        "/root/cert/${domain}/fullchain.pem|/root/cert/${domain}/privkey.pem"
    )
    local p cert key
    for p in "${pairs[@]}"; do
        cert="${p%%|*}"
        key="${p##*|}"
        if [ -f "$cert" ] && [ -f "$key" ]; then
            echo "${cert}|${key}"
            return 0
        fi
    done
    return 1
}

reload_nginx() {
    if nginx -t >/dev/null 2>&1; then
        systemctl reload nginx >/dev/null 2>&1 || nginx -s reload >/dev/null 2>&1 || true
        ok "Nginx 配置已重载"
        return 0
    fi
    echo -e "${R}[错误] Nginx 配置校验失败，请执行: nginx -t${N}"
    nginx -t || true
    return 1
}

ensure_nginx() {
    if ! command -v nginx >/dev/null 2>&1; then
        info "安装 nginx / curl ..."
        pkg_install nginx curl
    else
        command -v curl >/dev/null 2>&1 || pkg_install curl
    fi
    mkdir -p /etc/nginx/conf.d
    systemctl enable nginx >/dev/null 2>&1 || true
    systemctl start nginx >/dev/null 2>&1 || true
    strip_ipv6_listen
    ensure_websocket_map
    ensure_sub_module
    disable_default_site
}

# ======================== 云手机版 ========================
extract_share_code() {
    local input="$1" clean
    clean=$(echo "$input" | sed 's/#.*//' | tr -d '[:space:]')
    echo "$clean" | grep -oE '/ci/[A-Za-z0-9]+' | head -n 1 | sed 's|^/ci/||' || true
}

write_wrapper_html() {
    mkdir -p "$WRAP_DIR"
    cat > "${WRAP_DIR}/index.html" <<'EOF'
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>远程设备</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%;overflow:hidden;background:#111}
iframe{position:fixed;top:0;left:0;width:100%;height:100%;border:0}
</style>
</head>
<body>
<iframe id="frame" allow="camera;microphone;clipboard-read;clipboard-write;fullscreen;display-capture" allowfullscreen></iframe>
<script>
(function(){
  var m = location.pathname.match(/^\/v\/([^/]+)/);
  if (m) document.getElementById('frame').src = '/i/' + m[1];
})();
</script>
</body>
</html>
EOF
    chmod 755 "$WRAP_DIR"
    chmod 644 "${WRAP_DIR}/index.html"
}

write_cloud_nginx() {
    local local_domain="$1" target_host="$2" cert_file="$3" key_file="$4"
    local access_scheme="http" http_redirect="" ssl_block

    ssl_block="    listen 80;
    server_name ${local_domain};"

    if [ -n "$cert_file" ] && [ -n "$key_file" ]; then
        access_scheme="https"
        http_redirect="server {
    listen 80;
    server_name ${local_domain};
    return 301 https://\$host\$request_uri;
}
"
        ssl_block="    listen 443 ssl http2;
    server_name ${local_domain};
    ssl_certificate     ${cert_file};
    ssl_certificate_key ${key_file};
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    gzip off;
    proxy_set_header Accept-Encoding \"\";"
    fi

    cat > "${CLOUD_CONF}.tmp" <<EOF
# 云手机隐藏代理 - cloud-proxy-setup.sh
${http_redirect}server {
${ssl_block}

    location ~ ^/v/[A-Za-z0-9]+\$ {
        root ${WRAP_DIR};
        try_files /index.html =404;
    }

    location ~ ^/ci/([A-Za-z0-9]+)\$ {
        return 302 ${access_scheme}://\$host/v/\$1;
    }

    location ~ ^/i/([A-Za-z0-9]+)\$ {
        proxy_pass https://${target_host}/ci/\$1;
        proxy_ssl_server_name on;
        proxy_http_version 1.1;
        proxy_set_header Host ${target_host};
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto ${access_scheme};
        proxy_set_header X-Forwarded-Host \$host;
        proxy_redirect https://${target_host}/ ${access_scheme}://\$host/;
        proxy_redirect http://${target_host}/ ${access_scheme}://\$host/;
        proxy_cookie_domain ${target_host} \$host;
        proxy_buffering off;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }

    location ~ ^/(api|openapi)/ {
        proxy_pass https://${target_host};
        proxy_ssl_server_name on;
        proxy_http_version 1.1;
        proxy_set_header Host ${target_host};
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto ${access_scheme};
        proxy_set_header X-Forwarded-Host \$host;
        proxy_cookie_domain ${target_host} \$host;
        proxy_buffering off;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }

    location / {
        proxy_pass https://${target_host};
        proxy_ssl_server_name on;
        proxy_http_version 1.1;
        proxy_set_header Host ${target_host};
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        proxy_set_header X-Forwarded-Host \$host;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection \$connection_upgrade;
        proxy_redirect https://${target_host}/ ${access_scheme}://\$host/;
        proxy_redirect http://${target_host}/ ${access_scheme}://\$host/;
        sub_filter_once off;
        sub_filter_types text/css application/javascript application/json text/plain application/xml text/html;
        sub_filter "https://${target_host}" "${access_scheme}://\$host";
        sub_filter "http://${target_host}" "${access_scheme}://\$host";
        sub_filter "wss://${target_host}" "wss://\$host";
        sub_filter "ws://${target_host}" "wss://\$host";
        sub_filter "//${target_host}" "//\$host";
        sub_filter '"${target_host}"' '"\$host"';
        sub_filter "'${target_host}'" "'\$host'";
        proxy_cookie_domain ${target_host} \$host;
        proxy_cookie_path / /;
        proxy_buffering off;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}
EOF
    mv -f "${CLOUD_CONF}.tmp" "$CLOUD_CONF"

    cat > "${CLOUD_META}.tmp" <<EOF
LOCAL_DOMAIN=${local_domain}
TARGET_HOST=${target_host}
ACCESS_SCHEME=${access_scheme}
CONF_PATH=${CLOUD_CONF}
MODE=cloud
EOF
    mv -f "${CLOUD_META}.tmp" "$CLOUD_META"
}

add_note() {
    local share_code="$1" original_link="$2" remark="$3" ts
    ts=$(date +%s)
    printf '%s\t%s\t%s\t%s\n' "$ts" "$share_code" "$remark" "$original_link" >> "$CLOUD_NOTES"
}

render_notes() {
    local local_domain="${1:-}" access_scheme="${2:-}"
    [ -f "$CLOUD_NOTES" ] || return 0
    awk -F '\t' 'NF>=2 {print}' "$CLOUD_NOTES" 2>/dev/null | sort -nr -k1,1 | awk -F '\t' -v domain="$local_domain" -v scheme="$access_scheme" '{
        i++
        code=$2; remark=$3; orig=$4
        if (remark=="") remark="(无备注)"
        link=orig
        if (domain!="" && scheme!="") link=scheme "://" domain "/v/" code
        printf " %2d) %s | %s | %s\n", i, code, remark, link
    }'
}

delete_note_by_index() {
    local idx="$1" sel
    [ -f "$CLOUD_NOTES" ] || return 1
    [[ "$idx" =~ ^[0-9]+$ ]] || return 1
    sel=$(awk -F '\t' 'NF>=2 {print}' "$CLOUD_NOTES" 2>/dev/null | sort -nr -k1,1 | awk -v want="$idx" 'NR==want {print $0}')
    [ -n "$sel" ] || return 1
    awk -F '\t' -v sel="$sel" 'NF>=2 { if ($0!=sel) print $0 }' "$CLOUD_NOTES" > "${CLOUD_NOTES}.tmp"
    mv -f "${CLOUD_NOTES}.tmp" "$CLOUD_NOTES"
}

update_note_remark_by_index() {
    local idx="$1" new_remark="$2" sel sel_ts sel_code sel_orig
    [ -f "$CLOUD_NOTES" ] || return 1
    [[ "$idx" =~ ^[0-9]+$ ]] || return 1
    [ -n "$new_remark" ] || return 1
    sel=$(awk -F '\t' 'NF>=2 {print}' "$CLOUD_NOTES" 2>/dev/null | sort -nr -k1,1 | awk -v want="$idx" 'NR==want {print $0}')
    [ -n "$sel" ] || return 1
    sel_ts=$(printf '%s' "$sel" | awk -F '\t' '{print $1}')
    sel_code=$(printf '%s' "$sel" | awk -F '\t' '{print $2}')
    sel_orig=$(printf '%s' "$sel" | awk -F '\t' '{print $4}')
    awk -F '\t' -v ts="$sel_ts" -v code="$sel_code" -v remark="$new_remark" -v orig="$sel_orig" 'BEGIN{OFS="\t"} {
        if (NF>=2 && $1==ts && $2==code) print $1,$2,remark,orig
        else if (NF>=2) print $0
    }' "$CLOUD_NOTES" > "${CLOUD_NOTES}.tmp"
    mv -f "${CLOUD_NOTES}.tmp" "$CLOUD_NOTES"
}

load_cloud_config() {
    unset LOCAL_DOMAIN TARGET_HOST ACCESS_SCHEME CONF_PATH MODE
    if [ -f "$CLOUD_META" ]; then
        # shellcheck disable=SC1090
        source "$CLOUD_META"
        CONF_PATH="${CONF_PATH:-$CLOUD_CONF}"
        LOCAL_DOMAIN="${LOCAL_DOMAIN:-}"
        TARGET_HOST="${TARGET_HOST:-$DEFAULT_CLOUD_TARGET}"
        ACCESS_SCHEME="${ACCESS_SCHEME:-https}"
        return 0
    fi
    return 1
}

show_cloud_dashboard() {
    local local_domain="$1" target_host="$2" access_scheme="$3" share_code="${4:-}" conf_path="${5:-$CLOUD_CONF}"
    local ip_addr
    ip_addr=$(get_public_ip)
    echo -e "\n${G}==========================================================${N}"
    echo -e " ${C}本地域名      :${N} ${Y}${access_scheme}://${local_domain}${N}"
    [ -n "$ip_addr" ] && echo -e " ${C}服务器公网 IP :${N} ${Y}${ip_addr}${N}"
    echo -e " ${C}目标云机域名  :${N} ${Y}https://${target_host}${N}"
    echo -e " ${C}分享链接格式  :${N} ${Y}${access_scheme}://${local_domain}/v/分享码${N}"
    [ -n "$share_code" ] && echo -e " ${C}隐藏链接      :${N} ${Y}${access_scheme}://${local_domain}/v/${share_code}${N}"
    echo -e " ${C}Nginx 配置    :${N} ${Y}${conf_path}${N}"
    echo -e "${Y} 提示: 只分享 /v/分享码，不要分享 ${target_host} 原链${N}"
    echo -e "${G}==========================================================${N}"
}

install_cloud_phone() {
    local ip_raw local_domain target_host cert_file key_file ssl_info
    local test_link test_code remark access_scheme input_target

    info "安装云手机隐藏代理（多系统）..."
    ensure_nginx
    write_wrapper_html
    open_port 80
    open_port 443

    ip_raw=$(get_public_ip)
    local_domain=$(clean_host "$(ask "${G}你的域名（回车=公网IP）: ${N}")")
    [ -z "$local_domain" ] && local_domain="$ip_raw"
    [ -n "$local_domain" ] || { echo -e "${R}域名与公网IP均为空${N}"; sleep 2; return; }

    # 🛠️ 增加：允许自定义云机目标域名
    input_target=$(clean_host "$(ask "${G}目标云机域名（回车默认 ${DEFAULT_CLOUD_TARGET}）: ${N}")")
    target_host="${input_target:-$DEFAULT_CLOUD_TARGET}"

    cert_file=""; key_file=""; access_scheme="http"
    if ssl_info=$(detect_ssl_cert "$local_domain"); then
        cert_file="${ssl_info%%|*}"; key_file="${ssl_info##*|}"
        access_scheme="https"
        ok "检测到 SSL，启用 HTTPS"
    else
        warn "未检测到 SSL，使用 HTTP（可稍后上证书再重装）"
    fi

    # 避免与普通代理配置冲突
    if [ -f "$GENERIC_CONF" ]; then
        mv "$GENERIC_CONF" "${GENERIC_CONF}.bak.$(date +%Y%m%d%H%M%S)"
        warn "已备份普通代理配置，避免冲突"
    fi

    write_cloud_nginx "$local_domain" "$target_host" "$cert_file" "$key_file"
    systemctl restart nginx >/dev/null 2>&1 || true
    reload_nginx || { sleep 2; return; }

    test_link=$(ask "${G}粘贴一条星界原分享链接测试（可回车跳过）: ${N}")
    test_code=$(extract_share_code "$test_link")
    show_cloud_dashboard "$local_domain" "$target_host" "$access_scheme" "$test_code"
    if [ -n "$test_code" ]; then
        while true; do
            remark=$(ask "${G}备注（必填）: ${N}")
            [ -n "$remark" ] && break
        done
        add_note "$test_code" "$test_link" "$remark"
    fi
    pause
}

convert_cloud_link() {
    local share_input share_code converted remark
    if ! load_cloud_config; then
        echo -e "${R}请先执行 1 安装云手机版${N}"
        pause
        return
    fi
    echo -e "${C}示例: ${Y}https://${TARGET_HOST}/ci/1OYGq4nJpPW${N}"
    share_input=$(ask "${G}原始链接: ${N}")
    share_code=$(extract_share_code "$share_input")
    if [ -z "$share_code" ]; then
        share_code=$(ask "${G}未识别，请直接输入分享码: ${N}" | tr -d '[:space:]')
    fi
    [ -n "$share_code" ] || { echo -e "${R}分享码不能为空${N}"; sleep 1; return; }
    converted="${ACCESS_SCHEME}://${LOCAL_DOMAIN}/v/${share_code}"
    echo -e "\n${G}转换成功${N}"
    echo -e "${C}原链接: ${N}${share_input}"
    echo -e "${C}隐藏链接: ${N}${Y}${converted}${N}"
    while true; do
        remark=$(ask "${G}备注（必填）: ${N}")
        [ -n "$remark" ] && break
    done
    add_note "$share_code" "$share_input" "$remark"
    pause
}

view_cloud_config() {
    local edit_idx del_idx new_remark
    if load_cloud_config; then
        show_cloud_dashboard "$LOCAL_DOMAIN" "$TARGET_HOST" "$ACCESS_SCHEME" "" "$CONF_PATH"
    else
        echo -e "${R}尚未安装云手机代理${N}"
    fi
    echo ""
    echo -e "${C}备注列表:${N}"
    if [ -f "$CLOUD_NOTES" ]; then
        if load_cloud_config; then
            render_notes "$LOCAL_DOMAIN" "$ACCESS_SCHEME"
        else
            render_notes
        fi
        echo ""
        edit_idx=$(ask "${G}输入序号修改备注（回车跳过）: ${N}")
        if [ -n "$edit_idx" ]; then
            while true; do
                new_remark=$(ask "${G}新备注（必填）: ${N}")
                [ -n "$new_remark" ] && break
            done
            if update_note_remark_by_index "$edit_idx" "$new_remark"; then
                ok "已更新备注"
            else
                echo -e "${R}序号无效${N}"
            fi
        fi
        del_idx=$(ask "${G}输入序号删除备注（回车跳过）: ${N}")
        if [ -n "$del_idx" ]; then
            if delete_note_by_index "$del_idx"; then
                ok "已删除备注"
            else
                echo -e "${R}序号无效${N}"
            fi
        fi
    else
        warn "(暂无备注)"
    fi
    pause
}

uninstall_cloud() {
    local confirm skip_pause="${1:-}"
    if [ "$skip_pause" != "nopause" ]; then
        confirm=$(ask "${R}确认卸载云手机代理？输入 y 确认: ${N}")
        [[ "$confirm" == "y" || "$confirm" == "Y" ]] || { warn "已取消"; sleep 1; return; }
    fi
    rm -f "$CLOUD_CONF" "$CLOUD_META" "$CLOUD_NOTES"
    rm -rf "$WRAP_DIR"
    restore_default_site
    reload_nginx || true
    ok "云手机代理已卸载（Nginx 本体保留）"
    [ "$skip_pause" = "nopause" ] || pause
}

# ======================== 普通代理版 ========================
write_generic_nginx() {
    local local_domain="$1" target_url="$2" target_host="$3" cert_file="$4" key_file="$5"
    local access_scheme="http" http_redirect="" ssl_block

    ssl_block="    listen 80;
    server_name ${local_domain};"

    if [ -n "$cert_file" ] && [ -n "$key_file" ]; then
        access_scheme="https"
        http_redirect="server {
    listen 80;
    server_name ${local_domain};
    return 301 https://\$host\$request_uri;
}
"
        ssl_block="    listen 443 ssl http2;
    server_name ${local_domain};
    ssl_certificate     ${cert_file};
    ssl_certificate_key ${key_file};
    ssl_protocols       TLSv1.2 TLSv1.3;"
    fi

    cat > "${GENERIC_CONF}.tmp" <<EOF
# 普通反向代理 - cloud-proxy-setup.sh
${http_redirect}server {
${ssl_block}
    location / {
        proxy_pass ${target_url};
        proxy_ssl_server_name on;
        proxy_http_version 1.1;
        proxy_set_header Host ${target_host};
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection \$connection_upgrade;
        proxy_buffering off;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}
EOF
    mv -f "${GENERIC_CONF}.tmp" "$GENERIC_CONF"

    cat > "${GENERIC_META}.tmp" <<EOF
LOCAL_DOMAIN=${local_domain}
TARGET_URL=${target_url}
TARGET_HOST=${target_host}
ACCESS_SCHEME=${access_scheme}
SQUID_PORT=${SQUID_PORT}
MODE=generic
EOF
    mv -f "${GENERIC_META}.tmp" "$GENERIC_META"
}

setup_squid() {
    if ! command -v squid >/dev/null 2>&1 && ! command -v squid3 >/dev/null 2>&1; then
        info "安装 squid ..."
        pkg_install squid || pkg_install squid3 || warn "squid 安装失败，将仅提供 Nginx 反代"
    fi
    local squid_bin conf
    squid_bin=$(command -v squid || command -v squid3 || true)
    [ -n "$squid_bin" ] || return 0
    conf="/etc/squid/squid.conf"
    [ -f "$conf" ] || conf="/etc/squid3/squid.conf"
    [ -f "$conf" ] || { warn "未找到 squid.conf"; return 0; }
    cat > "$conf" <<EOF
http_port 0.0.0.0:${SQUID_PORT}
acl all_src src 0.0.0.0/0
http_access allow all_src
coredump_dir /var/spool/squid
EOF
    open_port "$SQUID_PORT"
    systemctl enable squid >/dev/null 2>&1 || systemctl enable squid3 >/dev/null 2>&1 || true
    systemctl restart squid >/dev/null 2>&1 || systemctl restart squid3 >/dev/null 2>&1 || true
}

load_generic_config() {
    unset LOCAL_DOMAIN TARGET_URL TARGET_HOST ACCESS_SCHEME SQUID_PORT MODE
    if [ -f "$GENERIC_META" ]; then
        # shellcheck disable=SC1090
        source "$GENERIC_META"
        return 0
    fi
    if [ -f "$GENERIC_CONF" ]; then
        LOCAL_DOMAIN=$(grep -E '^[[:space:]]*server_name' "$GENERIC_CONF" | head -n1 | awk '{print $2}' | sed 's/;//')
        TARGET_URL=$(grep -E '^[[:space:]]*proxy_pass' "$GENERIC_CONF" | head -n1 | awk '{print $2}' | sed 's/;//')
        TARGET_HOST=$(echo "$TARGET_URL" | sed -e 's|^[^/]*//||' -e 's|/.*$||')
        ACCESS_SCHEME=$(grep -q 'listen 443 ssl' "$GENERIC_CONF" && echo https || echo http)
        SQUID_PORT="${SQUID_PORT:-9678}"
        return 0
    fi
    return 1
}

show_generic_dashboard() {
    local ip_addr
    ip_addr=$(get_public_ip)
    echo -e "\n${G}==========================================================${N}"
    echo -e " ${C}▶ Squid 端口    :${N}  ${Y}${SQUID_PORT:-9678}${N}"
    echo -e " ${C}▶ 域名访问地址  :${N}  ${Y}${ACCESS_SCHEME}://${LOCAL_DOMAIN}${N}"
    [ -n "$ip_addr" ] && echo -e " ${C}▶ IP访问地址    :${N}  ${Y}${ACCESS_SCHEME}://${ip_addr}${N}"
    echo -e " ${C}▶ 目标转发地址  :${N}  ${Y}${TARGET_URL}${N}"
    echo -e " ${C}▶ 配置文件      :${N}  ${Y}${GENERIC_CONF}${N}"
    echo -e "${G}==========================================================${N}"
}

install_generic_proxy() {
    local ip_raw local_domain target_url target_host cert_file key_file ssl_info access_scheme

    info "安装普通代理版（Nginx 反代 + Squid）..."
    warn "普通代理版不适合云手机/星界分享链；云手机请用菜单 1"
    ensure_nginx
    setup_squid
    open_port 80
    open_port 443

    ip_raw=$(get_public_ip)
    local_domain=$(clean_host "$(ask "${G}访问入口（回车=公网IP）: ${N}")")
    [ -z "$local_domain" ] && local_domain="$ip_raw"
    [ -n "$local_domain" ] || { echo -e "${R}入口为空${N}"; sleep 2; return; }

    target_url=$(ask "${G}目标地址（例如 www.google.com 或 https://example.com/path）: ${N}" | tr -d '[:space:]')
    [ -n "$target_url" ] || { echo -e "${R}目标不能为空${N}"; sleep 2; return; }
    [[ "$target_url" == http* ]] || target_url="https://${target_url}"
    target_host=$(echo "$target_url" | sed -e 's|^[^/]*//||' -e 's|/.*$||' -e 's|:.*$||')
    if echo "$target_host" | grep -qiE 'chinac\.com|xingjie|星界'; then
        warn "检测到云机相关域名，请改用「1) 安装云手机版」，否则会进登录页"
        sleep 2
    fi

    cert_file=""; key_file=""; access_scheme="http"
    if ssl_info=$(detect_ssl_cert "$local_domain"); then
        cert_file="${ssl_info%%|*}"; key_file="${ssl_info##*|}"
        access_scheme="https"
        ok "检测到 SSL，启用 HTTPS"
    else
        warn "未检测到 SSL，使用 HTTP"
    fi

    if [ -f "$CLOUD_CONF" ]; then
        warn "检测到云手机配置并存；两者可用不同域名，请注意 server_name 不要冲突"
    fi

    write_generic_nginx "$local_domain" "$target_url" "$target_host" "$cert_file" "$key_file"
    ACCESS_SCHEME="$access_scheme"
    LOCAL_DOMAIN="$local_domain"
    TARGET_URL="$target_url"
    systemctl restart nginx >/dev/null 2>&1 || true
    reload_nginx || { sleep 2; return; }
    show_generic_dashboard
    pause
}

view_generic_config() {
    if load_generic_config; then
        show_generic_dashboard
    else
        echo -e "${R}尚未安装普通代理${N}"
    fi
    pause
}

uninstall_generic() {
    local confirm skip_pause="${1:-}"
    if [ "$skip_pause" != "nopause" ]; then
        confirm=$(ask "${R}确认卸载普通代理配置？输入 y 确认: ${N}")
        [[ "$confirm" == "y" || "$confirm" == "Y" ]] || { warn "已取消"; sleep 1; return; }
    fi
    rm -f "$GENERIC_CONF" "$GENERIC_META"
    systemctl stop squid >/dev/null 2>&1 || systemctl stop squid3 >/dev/null 2>&1 || true
    reload_nginx || true
    ok "普通代理配置已删除（Nginx/Squid 软件包保留）"
    [ "$skip_pause" = "nopause" ] || pause
}

uninstall_menu() {
    local choice confirm
    echo ""
    echo -e "${Y} 1) 仅卸载云手机版${N}"
    echo -e "${Y} 2) 仅卸载普通代理版${N}"
    echo -e "${R} 3) 两者都卸载${N}"
    echo -e "${C} 0) 返回${N}"
    choice=$(ask "请选择: ")
    case "$choice" in
        1) uninstall_cloud ;;
        2) uninstall_generic ;;
        3)
            confirm=$(ask "${R}确认同时卸载两者？输入 y 确认: ${N}")
            [[ "$confirm" == "y" || "$confirm" == "Y" ]] || { warn "已取消"; sleep 1; return; }
            uninstall_cloud nopause
            uninstall_generic nopause
            pause
            ;;
        *) return ;;
    esac
}

# ======================== 主菜单 ========================
main_menu() {
    local choice
    while true; do
        clear
        echo -e "${C}##########################################################${N}"
        echo -e "${C}#     云机 / 普通代理 统一部署工具 (多系统可移植)       #${N}"
        echo -e "${C}#     系统: ${OS_ID}  |  包管理: ${PKG}                      #${N}"
        echo -e "${C}##########################################################${N}"
        echo ""
        echo -e "${G} 1) 安装云手机版${N}   ${Y}(隐藏 chinac 链接 + 加速)${N}"
        echo -e "${G} 2) 安装普通代理版${N} ${Y}(通用站点反代 + Squid:${SQUID_PORT}，非云手机)${N}"
        echo -e "${C} 3) 转换云手机分享链接 / 添加备注${N}"
        echo -e "${C} 4) 查看配置（云手机备注可改删）${N}"
        echo -e "${C} 5) 查看普通代理配置${N}"
        echo -e "${R} 6) 卸载${N}"
        echo -e "${Y} 0) 退出${N}"
        echo ""
        choice=$(ask "请选择: ")
        case "$choice" in
            1) install_cloud_phone ;;
            2) install_generic_proxy ;;
            3) convert_cloud_link ;;
            4) view_cloud_config ;;
            5) view_generic_config ;;
            6) uninstall_menu ;;
            0) echo -e "${Y}退出${N}"; exit 0 ;;
            *) echo -e "${R}无效选项${N}"; sleep 1 ;;
        esac
    done
}

check_root
detect_os
main_menu