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

set -e

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 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] 正在检查并同步系统标准时间..."
    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/^[ \t]*//')
    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)"
}

restart_portainer() {
    log_info "正在重启 Portainer 容器以重置 5 分钟初始化倒计时..."
    if [ "$(sudo docker ps -a -q -f name=portainer 2>/dev/null)" ]; then
        sudo docker restart portainer >/dev/null 2>&1
        log_succ "Portainer 已重新启动！请立即访问 http://${LOCAL_IP}:9000 设置管理员密码。"
    else
        log_warn "未找到 Portainer 容器，尝试重新部署..."
        deploy_portainer
    fi
}

deploy_portainer() {
    log_info "检查/部署 Portainer 可视化管理面板..."
    sudo docker rm -f portainer 2>/dev/null || true
    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
    log_succ "Portainer 面板已启动 (访问地址: http://${LOCAL_IP}:9000)"
    log_warn "提示：首次访问有 5 分钟初始化限制，若提示 timed out，请在菜单选择重置即可。"
}

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] 检查并自动补全系统基础依赖..."
    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 引擎及 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 || {
            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

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

    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 "镜像加速节点配置完成！"

    log_info "[5/6] 预先拉取 RustDesk Server 镜像..."
    sudo docker pull rustdesk/rustdesk-server:latest >/dev/null 2>&1 || true
    log_succ "RustDesk Server 镜像拉取完成！"

    log_info "[6/6] 启动 Portainer 管理面板..."
    deploy_portainer

    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
        [ -n "$key" ] && break
        sleep 1
    done

    echo "${key:-"无法读取 Key (生成中或权限异常)"}"
}

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"; 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 "正在启动 RustDesk 容器 (${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

    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
    DO_OP=${DO_OP:-"y"}
    if [ "$DO_OP" != "y" ] && [ "$DO_OP" != "Y" ]; then
        return
    fi

    if [ -z "$OP_IP" ]; then
        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 ""
    fi

    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})..."

        if sshpass -p "$OP_PASS" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@$OP_IP "sh -s" "$SAFE_INST_NAME" "$LOCAL_IP" "$P_21115" "$P_21116" "$P_21117" "$P_21118" "$P_21119" << 'EOF' >/dev/null 2>&1
INST_NAME="$1"
LOCAL_IP="$2"
shift 2

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

for p in "$@"; do
    sec=$(uci add firewall redirect)
    uci set firewall.$sec.name="rd_${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
EOF
        then
            log_succ "实例 [${INST_NAME}] 端口转发同步成功！"
        else
            log_err "连接 OpenWrt 失败，请检查网络或 SSH 密码！"
        fi
    done

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

delete_op_rules() {
    local INST_NAME="$1"
    local SAFE_INST_NAME=$(sanitize_name "$INST_NAME")

    if [ -z "$OP_IP" ]; then
        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 ""
    fi

    log_info "正在清理 OpenWrt 防火墙中实例 [${INST_NAME}] 的转发规则..."

    if sshpass -p "$OP_PASS" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@$OP_IP "sh -s" "$SAFE_INST_NAME" << 'EOF' >/dev/null 2>&1
INST_NAME="$1"
for sec in $(uci show firewall | grep "rd_${INST_NAME}_" | cut -d'.' -f2 | cut -d'=' -f1 | sort -u); do
    uci delete firewall.$sec 2>/dev/null || true
done
uci commit firewall
/etc/init.d/firewall reload >/dev/null 2>&1 || /etc/init.d/firewall restart >/dev/null 2>&1
EOF
    then
        log_succ "实例 [${INST_NAME}] 的 OpenWrt 防火墙规则已成功删除！"
    else
        log_err "清理 OpenWrt 防火墙规则失败，请检查网络或 SSH 密码！"
    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}6.${NC} 重启 Portainer 面板 (重置 5分钟初始化倒计时)"
    echo -e "  ${YELLOW}0.${NC} 退出脚本"
    echo -e "${CYAN}--------------------------------------------------------------${NC}"
    echo -n "请选择操作 [0-6]: "
    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 已被彻底清理！"

                echo -n "是否一并删除 OpenWrt 防火墙中该实例的端口转发规则? (Y/n): "
                read DEL_OP_RULE
                DEL_OP_RULE=${DEL_OP_RULE:-"y"}
                if [ "$DEL_OP_RULE" = "y" ] || [ "$DEL_OP_RULE" = "Y" ]; then
                    delete_op_rules "$DEL_NAME"
                fi
            else
                log_err "未找到该实例。"
            fi
            ;;
        5) sync_openwrt ;;
        6) restart_portainer ;;
        0)
            log_info "已安全退出。"
            exit 0
            ;;
        *) log_err "无效选项，请重新选择。" ;;
    esac
done
