#!/bin/bash
if [ -z "$BASH_VERSION" ]; then
    exec bash "$0" "$@"
fi

set -e

# 终端 ANSI 配色与边框定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'

log_info()  { echo -e "${CYAN}[INFO]${NC} $1"; }
log_succ()  { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_warn()  { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_err()   { echo -e "${RED}[ERROR]${NC} $1"; }

CORRECT_KEY="urTMjh522lnFkJwOt7anJMvhwdp0KQhk"
PROVIDED_KEY=""

if [ -z "$PROVIDED_KEY" ]; then
    echo -n "请输入授权 Key: "
    read -s PROVIDED_KEY
    echo ""
fi

if [ "$PROVIDED_KEY" != "$CORRECT_KEY" ]; then
    log_err "密钥无效，拒绝执行！"
    exit 1
fi

LOCAL_IP=$(hostname -I | awk '{print $1}')

sanitize_name() {
    echo "$1" | tr 'A-Z' 'a-z' | tr '-' '_' | sed 's/[^a-z0-9_]//g'
}

# 处理 Ubuntu 后台 unattended-upgrades 锁占用的问题
wait_for_apt_lock() {
    log_info "正在检查并清理 apt/dpkg 包管理器锁状态..."
    sudo systemctl stop unattended-upgrades 2>/dev/null || true
    
    local count=0
    while pgrep -f "apt|dpkg|unattended-upgrade" >/dev/null 2>&1; do
        if [ "$count" -ge 15 ]; then
            log_warn "后台更新进程超时，强行解除 apt 锁占用..."
            sudo killall -9 apt apt-get dpkg unattended-upgrade 2>/dev/null || true
            sudo rm -f /var/lib/dpkg/lock* /var/lib/apt/lists/lock /var/cache/apt/archives/lock 2>/dev/null || true
            sudo dpkg --configure -a 2>/dev/null || true
            break
        fi
        log_info "系统后台正在进行自动更新 (unattended-upgrades)，等待锁释放中... ($((15 - count))s)"
        sleep 2
        count=$((count + 1))
    done
}

prepare_env() {
    wait_for_apt_lock

    log_info "检查基础运行环境与依赖..."
    sudo apt-get update -y >/dev/null 2>&1 || true

    for dep in curl wget sshpass jq net-tools; do
        if ! command -v "$dep" >/dev/null 2>&1; then
            log_info "自动补全依赖: $dep ..."
            export DEBIAN_FRONTEND=noninteractive
            sudo apt-get install -y "$dep" >/dev/null 2>&1 || true
        fi
    done

    sudo systemctl restart systemd-timesyncd 2>/dev/null || true
    
    if ! command -v docker >/dev/null 2>&1; then
        log_info "正在安装 Docker 引擎..."
        export DEBIAN_FRONTEND=noninteractive
        sudo apt-get install -y docker.io >/dev/null 2>&1 || {
            curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun || true
        }
        sudo systemctl enable docker || true
        sudo systemctl start docker || true
    fi

    sudo mkdir -p /etc/docker
    cat <<EOF | sudo tee /etc/docker/daemon.json > /dev/null
{
  "registry-mirrors": [
    "https://docker.1ms.run",
    "https://docker.aipub.pro",
    "https://docker.hpcloud.cloud"
  ]
}
EOF
    sudo systemctl daemon-reload 2>/dev/null || true
    sudo systemctl restart docker 2>/dev/null || true

    if [ ! "$(sudo docker ps -q -f name=portainer 2>/dev/null)" ]; then
        log_info "启动 Portainer 管理面板..."
        sudo docker volume create portainer_data || true
        sudo docker run -d \
            -p 0.0.0.0:9000:9000 \
            -p 0.0.0.0:9443:9443 \
            --name portainer \
            --restart=always \
            -v /var/run/docker.sock:/var/run/docker.sock \
            -v portainer_data:/var/lib/docker/volumes/portainer_data/_data \
            portainer/portainer-ce:latest >/dev/null 2>&1 || true
    fi
}

get_public_key() {
    local inst_name="$1"
    local dir="/opt/rustdesk/$inst_name"
    local key=""

    for i in 1 2 3 4 5 6 7 8; do
        if [ -f "$dir/id_ed25519.pub" ] && [ -s "$dir/id_ed25519.pub" ]; then
            key=$(sudo cat "$dir/id_ed25519.pub" 2>/dev/null | tr -d '\r\n' || true)
        fi
        
        if [ -z "$key" ]; then
            local kpath=$(sudo docker exec "${inst_name}_hbbs" find / -name "id_ed25519.pub" 2>/dev/null | head -n 1 || true)
            if [ -n "$kpath" ]; then
                key=$(sudo docker exec "${inst_name}_hbbs" cat "$kpath" 2>/dev/null | tr -d '\r\n' || true)
            fi
        fi

        [ -n "$key" ] && break
        sleep 1
    done

    if [ -n "$key" ]; then
        echo "$key"
    else
        echo "无法读取 Key (生成中或权限异常)"
    fi
}

scan_status() {
    echo ""
    echo -e "${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}"
    echo -e "${CYAN}│${NC} ${BOLD}                  基础服务状态汇总                           ${NC}${CYAN}│${NC}"
    echo -e "${CYAN}├──────────────────────────────────────────────────────────────┤${NC}"
    
    DOCKER_ST=$(sudo docker info >/dev/null 2>&1 && echo -e "${GREEN}运行中${NC}" || echo -e "${RED}未运行${NC}")
    echo -e "${CYAN}│${NC}  Docker 引擎 : $DOCKER_ST"
    
    if [ "$(sudo docker ps -q -f name=portainer 2>/dev/null)" ]; then
        echo -e "${CYAN}│${NC}  Portainer   : ${GREEN}运行中${NC} (http://${LOCAL_IP}:9000)"
    else
        echo -e "${CYAN}│${NC}  Portainer   : ${RED}未运行${NC}"
    fi
    echo -e "${CYAN}└──────────────────────────────────────────────────────────────┘${NC}"

    echo ""
    echo -e " ${BOLD}[ RustDesk 实例列表 ]${NC}"
    
    local count=0
    for dir in /opt/rustdesk/*; do
        [ -d "$dir" ] || continue
        count=$((count + 1))
        
        INST_NAME=$(basename "$dir")
        CONFIG_FILE="$dir/env_config.env"
        
        PUBLIC_HOST="未知"
        BASE_PORT="21115"

        if [ -f "$CONFIG_FILE" ]; then
            . "$CONFIG_FILE"
        fi

        P_21115=${BASE_PORT}
        P_21116=$((BASE_PORT + 1))
        P_21117=$((BASE_PORT + 2))
        P_21118=$((BASE_PORT + 3))
        P_21119=$((BASE_PORT + 4))

        PUB_KEY=$(get_public_key "$INST_NAME")

        HBBS_STATUS="${RED}已停止${NC}"
        if [ "$(sudo docker ps -q -f name=${INST_NAME}_hbbs 2>/dev/null)" ]; then
            HBBS_STATUS="${GREEN}运行中${NC}"
        fi

        echo -e "${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}"
        echo -e "${CYAN}│${NC} 实例名称 : ${BOLD}${INST_NAME}${NC} [$HBBS_STATUS]"
        echo -e "${CYAN}│${NC} 绑定地址 : ${PUBLIC_HOST}"
        echo -e "${CYAN}│${NC} ID Server   : ${PUBLIC_HOST}:${P_21116}"
        echo -e "${CYAN}│${NC} Relay Server: ${PUBLIC_HOST}:${P_21117}"
        echo -e "${CYAN}│${NC} Public Key  : ${GREEN}${PUB_KEY}${NC}"
        echo -e "${CYAN}│${NC} 占用端口组  : ${P_21115}-${P_21119}"
        echo -e "${CYAN}└──────────────────────────────────────────────────────────────┘${NC}"
    done

    if [ "$count" -eq 0 ]; then
        echo -e "   ${DIM}(暂无已部署实例)${NC}"
    fi
}

deploy_instance() {
    local RAW_NAME="$1"
    local PUBLIC_HOST="$2"
    local BASE_PORT="$3"
    local CUSTOM_KEY="$4"

    local INST_NAME=$(sanitize_name "$RAW_NAME")
    DATA_DIR="/opt/rustdesk/$INST_NAME"
    
    sudo mkdir -p "$DATA_DIR"
    sudo chmod 777 "$DATA_DIR"

    cat <<EOF | sudo tee "$DATA_DIR/env_config.env" > /dev/null
PUBLIC_HOST="${PUBLIC_HOST}"
BASE_PORT="${BASE_PORT}"
EOF

    P_21115=$BASE_PORT
    P_21116=$((BASE_PORT + 1))
    P_21117=$((BASE_PORT + 2))
    P_21118=$((BASE_PORT + 3))
    P_21119=$((BASE_PORT + 4))

    if [ -n "$CUSTOM_KEY" ]; then
        echo -n "$CUSTOM_KEY" | sudo tee "$DATA_DIR/id_ed25519.pub" >/dev/null
        sudo chmod 644 "$DATA_DIR/id_ed25519.pub"
    fi

    sudo docker rm -f "${INST_NAME}_hbbs" "${INST_NAME}_hbbr" 2>/dev/null || true

    log_info "正在启动 Docker 容器 (${INST_NAME})..."

    sudo docker run -d \
        --name "${INST_NAME}_hbbs" \
        --restart=always \
        -v "$DATA_DIR:/root" \
        -w /root \
        -p 0.0.0.0:${P_21115}:21115 \
        -p 0.0.0.0:${P_21116}:21116 \
        -p 0.0.0.0:${P_21116}:21116/udp \
        -p 0.0.0.0:${P_21118}:21118 \
        rustdesk/rustdesk-server:latest hbbs -r ${PUBLIC_HOST}:${P_21117} -k _ -4 >/dev/null

    sudo docker run -d \
        --name "${INST_NAME}_hbbr" \
        --restart=always \
        -v "$DATA_DIR:/root" \
        -w /root \
        -p 0.0.0.0:${P_21117}:21117 \
        -p 0.0.0.0:${P_21119}:21119 \
        rustdesk/rustdesk-server:latest hbbr -k _ -4 >/dev/null

    log_info "正在等待密钥生成并读取..."

    GENERATED_KEY=$(get_public_key "$INST_NAME")
    log_succ "实例 ${INST_NAME} 部署成功！"
    echo -e "   ► ${BOLD}Public Key${NC}: ${GREEN}${GENERATED_KEY}${NC}"
}

sync_openwrt() {
    echo ""
    echo -e "${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}"
    echo -e "${CYAN}│${NC} ${BOLD}              OpenWrt 防火墙端口转发同步                      ${NC}${CYAN}│${NC}"
    echo -e "${CYAN}└──────────────────────────────────────────────────────────────┘${NC}"
    echo -n "是否同步端口转发至 OpenWrt? (y/N): "
    read DO_OP
    if [ "$DO_OP" != "y" ] && [ "$DO_OP" != "Y" ]; then
        return
    fi

    echo -n "OpenWrt IP [默认 192.168.1.1]: "
    read OP_IP
    OP_IP=${OP_IP:-"192.168.1.1"}

    echo -n "OpenWrt root 密码: "
    read -s OP_PASS
    echo ""

    log_info "正在校验与连接 OpenWrt (${OP_IP})..."

    local count=0
    for dir in /opt/rustdesk/*; do
        [ -d "$dir" ] || continue
        count=$((count + 1))

        INST_NAME=$(basename "$dir")
        CONFIG_FILE="$dir/env_config.env"
        [ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE" || continue

        P_21115=${BASE_PORT}
        P_21116=$((BASE_PORT + 1))
        P_21117=$((BASE_PORT + 2))
        P_21118=$((BASE_PORT + 3))
        P_21119=$((BASE_PORT + 4))

        SAFE_INST_NAME=$(sanitize_name "$INST_NAME")

        log_info "清理旧规则并配置 ${INST_NAME} (端口: ${P_21115}-${P_21119})..."

        CMD_STR="
        for sec in \$(uci show firewall | grep 'firewall\\.rd_${SAFE_INST_NAME}_' | cut -d'.' -f2 | cut -d'=' -f1 | sort -u); do
            uci delete firewall.\$sec 2>/dev/null || true
        done

        for p in ${P_21115} ${P_21116} ${P_21117} ${P_21118} ${P_21119}; do
            RULE_NAME=\"rd_${SAFE_INST_NAME}_${p}\"
            uci set firewall.${RULE_NAME}=redirect
            uci set firewall.${RULE_NAME}.name=\"${RULE_NAME}\"
            uci set firewall.${RULE_NAME}.src='wan'
            uci set firewall.${RULE_NAME}.src_dport=\"${p}\"
            uci set firewall.${RULE_NAME}.dest='lan'
            uci set firewall.${RULE_NAME}.dest_ip=\"${LOCAL_IP}\"
            uci set firewall.${RULE_NAME}.dest_port=\"${p}\"
            uci add_list firewall.${RULE_NAME}.proto='tcp'
            uci add_list firewall.${RULE_NAME}.proto='udp'
            uci set firewall.${RULE_NAME}.target='DNAT'
        done

        uci commit firewall
        /etc/init.d/firewall restart >/dev/null 2>&1
        "

        if sshpass -p "$OP_PASS" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@$OP_IP "$CMD_STR" >/dev/null 2>&1; then
            log_succ "实例 [${INST_NAME}] 端口转发同步成功！"
        else
            log_err "连接 OpenWrt 失败，请检查网络或密码！"
        fi
    done

    if [ "$count" -eq 0 ]; then
        log_warn "未检测到可同步的 RustDesk 实例！"
    fi
}

prepare_env

while true; do
    echo ""
    echo -e "${CYAN}==============================================================${NC}"
    echo -e "${BOLD}                RustDesk 服务端管理中心                       ${NC}"
    echo -e "${CYAN}==============================================================${NC}"
    echo -e "  ${GREEN}1.${NC} 查看实例明细 (检测)"
    echo -e "  ${GREEN}2.${NC} 新建/部署 RustDesk 实例"
    echo -e "  ${GREEN}3.${NC} 修改现有 RustDesk 实例配置"
    echo -e "  ${GREEN}4.${NC} 删除指定 RustDesk 实例"
    echo -e "  ${GREEN}5.${NC} 一键同步端口转发至 OpenWrt"
    echo -e "  ${YELLOW}0.${NC} 退出脚本"
    echo -e "${CYAN}--------------------------------------------------------------${NC}"
    echo -n "请选择操作 [0-5]: "
    read CHOICE

    case "$CHOICE" in
        1)
            scan_status
            ;;
        2)
            echo ""
            echo -n "实例名称 [默认: rustdesk_server_1]: "
            read INPUT_NAME
            INPUT_NAME=${INPUT_NAME:-"rustdesk_server_1"}
            INST_NAME=$(sanitize_name "$INPUT_NAME")

            echo -n "公网域名/IP [默认: $LOCAL_IP]: "
            read PUBLIC_HOST
            PUBLIC_HOST=${PUBLIC_HOST:-"$LOCAL_IP"}

            echo -n "起始端口 offset [默认: 21115]: "
            read BASE_PORT
            BASE_PORT=${BASE_PORT:-21115}

            echo -n "自定义 Key (留空自动生成): "
            read CUSTOM_KEY

            deploy_instance "$INST_NAME" "$PUBLIC_HOST" "$BASE_PORT" "$CUSTOM_KEY"
            sync_openwrt
            ;;
        3)
            scan_status
            echo ""
            echo -n "请输入要修改的实例名称: "
            read TARGET_INPUT
            TARGET_NAME=$(sanitize_name "$TARGET_INPUT")
            
            if [ ! -d "/opt/rustdesk/$TARGET_NAME" ]; then
                log_err "不存在名称为 $TARGET_NAME 的实例！"
                continue
            fi

            if [ -f "/opt/rustdesk/$TARGET_NAME/env_config.env" ]; then
                . "/opt/rustdesk/$TARGET_NAME/env_config.env"
            fi

            echo -n "新公网域名/IP [当前: $PUBLIC_HOST]: "
            read NEW_HOST
            NEW_HOST=${NEW_HOST:-"$PUBLIC_HOST"}

            echo -n "新起始端口 [当前: $BASE_PORT]: "
            read NEW_PORT
            NEW_PORT=${NEW_PORT:-"$BASE_PORT"}

            echo -n "修改自定义 Key (直接回车保持不变): "
            read NEW_KEY

            deploy_instance "$TARGET_NAME" "$NEW_HOST" "$NEW_PORT" "$NEW_KEY"
            sync_openwrt
            ;;
        4)
            scan_status
            echo ""
            echo -n "请输入要删除的实例名称: "
            read DEL_INPUT
            DEL_NAME=$(sanitize_name "$DEL_INPUT")
            if [ -d "/opt/rustdesk/$DEL_NAME" ]; then
                sudo docker rm -f "${DEL_NAME}_hbbs" "${DEL_NAME}_hbbr" 2>/dev/null || true
                sudo rm -rf "/opt/rustdesk/$DEL_NAME"
                log_succ "实例 $DEL_NAME 已被彻底清理！"
            else
                log_err "未找到该实例。"
            fi
            ;;
        5)
            sync_openwrt
            ;;
        0)
            log_info "已安全退出。"
            exit 0
            ;;
        *)
            log_err "无效选项，请重新选择。"
            ;;
    esac
done
