#!/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'
}

check_port_conflict() {
    local base_port="$1"
    local current_inst="$2"
    local has_conflict=0

    for i in 0 1 2 3 4; do
        local check_p=$((base_port + i))
        if netstat -tuln 2>/dev/null | grep -q ":${check_p} " || ss -tuln 2>/dev/null | grep -q ":${check_p} "; then
            log_err "端口 ${check_p} 已被系统或其他服务占用！"
            has_conflict=1
        fi
    done

    return $has_conflict
}

wait_for_apt_lock() {
    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
        sleep 2
        count=$((count + 1))
    done
}

sync_system_time() {
    log_info "[0/6] 正在检查并同步系统标准时间 (防止 apt 源签名验证失败)..."
    
    HTTP_DATE=$(wget -S --spider --no-check-certificate "https://www.baidu.com" 2>&1 | grep -i "^ *date:" | head -n 1 | cut -d':' -f2- | sed 's/^[ 	]*//')
    if [ -n "$HTTP_DATE" ]; then
        sudo date -s "$HTTP_DATE" >/dev/null 2>&1 || true
    fi

    sudo systemctl restart systemd-timesyncd 2>/dev/null || true
    log_succ "系统时间已校准为: $(date)"
}

prepare_env() {
    echo ""
    echo -e "${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}"
    echo -e "${CYAN}│${NC} ${BOLD}               环境初始化与基础依赖组件校验                 ${NC}${CYAN}│${NC}"
    echo -e "${CYAN}└──────────────────────────────────────────────────────────────┘${NC}"

    sync_system_time

    log_info "[1/6] 检查系统 apt/dpkg 包管理器锁状态..."
    wait_for_apt_lock

    log_info "[2/6] 检查并自动补全系统基础依赖 (curl, wget, sshpass, jq, net-tools)..."
    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
            export DEBIAN_FRONTEND=noninteractive
            sudo apt-get install -y "$dep" >/dev/null 2>&1 || true
        fi
    done
    log_succ "基础依赖工具安装完成！"

    log_info "[3/6] 校验/安装 Docker 引擎及 Docker Compose 插件..."
    if ! command -v docker >/dev/null 2>&1; then
        export DEBIAN_FRONTEND=noninteractive
        sudo apt-get update -y >/dev/null 2>&1 || true
        sudo apt-get install -y docker.io docker-compose-plugin >/dev/null 2>&1 || {
            log_warn "apt 安装 docker.io 失败，尝试通过官方脚本安装..."
            curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun || true
        }
        sudo systemctl enable docker 2>/dev/null || true
        sudo systemctl start docker 2>/dev/null || true
    fi

    if ! command -v docker >/dev/null 2>&1; then
        log_err "Docker 安装失败！请检查系统网络连接。"
        exit 1
    fi

    if ! docker compose version >/dev/null 2>&1; then
        sudo apt-get install -y docker-compose-plugin >/dev/null 2>&1 || true
    fi

    DOCKER_VER=$(docker --version 2>/dev/null | awk '{print $3}' | tr -d ',' || echo "未知")
    log_succ "Docker (v${DOCKER_VER}) 与 Compose 插件就绪！"

    log_info "[4/6] 配置 Docker Registry 镜像加速源..."
    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
    log_succ "Docker 镜像加速节点配置更新成功！"

    log_info "[5/6] 检查并部署 Portainer 可视化管理面板..."
    if [ ! "$(sudo docker ps -q -f name=portainer 2>/dev/null)" ]; then
        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
    log_succ "Portainer 管理面板已就绪 (访问地址: http://${LOCAL_IP}:9000)！"

    log_info "[6/6] 预先拉取 RustDesk Server 镜像 (确保后续创建实例秒级启动)..."
    if sudo docker pull rustdesk/rustdesk-server:latest >/dev/null 2>&1; then
        log_succ "RustDesk Server 最新镜像预加载完成！"
    else
        log_warn "RustDesk 镜像预拉取超时或失败，后续部署时将自动重试。"
    fi

    echo -e "${GREEN}==============================================================${NC}"
    echo -e "${GREEN}            所有基础环境与核心镜像已准备就绪！               ${NC}"
    echo -e "${GREEN}==============================================================${NC}
"
}

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

    for i in $(seq 1 10); do
        sudo chmod -R 755 "$dir" 2>/dev/null || true
        
        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")
    
    if ! check_port_conflict "$BASE_PORT" "$INST_NAME"; then
        log_err "端口冲突检测失败，取消部署此实例。"
        return 1
    fi

    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 _ >/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 _ >/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 "正在向 OpenWrt 写入 ${INST_NAME} 端口转发 (${P_21115}-${P_21119})..."

        CMD_STR="
        for sec in \$(uci show firewall | grep 'name=.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
            sec=\$(uci add firewall redirect)
            uci set firewall.\$sec.name="rd_${SAFE_INST_NAME}_${p}"
            uci set firewall.\$sec.src='wan'
            uci set firewall.\$sec.src_dport="${p}"
            uci set firewall.\$sec.dest='lan'
            uci set firewall.\$sec.dest_ip="${LOCAL_IP}"
            uci set firewall.\$sec.dest_port="${p}"
            uci set firewall.\$sec.proto='tcp udp'
            uci set firewall.\$sec.target='DNAT'
        done

        uci commit firewall
        /etc/init.d/firewall reload >/dev/null 2>&1 || /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 失败，请检查网络或 SSH 密码！"
        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

            if deploy_instance "$INST_NAME" "$PUBLIC_HOST" "$BASE_PORT" "$CUSTOM_KEY"; then
                sync_openwrt
            fi
            ;;
        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

            if deploy_instance "$TARGET_NAME" "$NEW_HOST" "$NEW_PORT" "$NEW_KEY"; then
                sync_openwrt
            fi
            ;;
        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
