#!/bin/bash

color () {
	RES_COL=60
	MOVE_TO_COL="echo -en \\033[${RES_COL}G"
	SETCOLOR_SUCCESS="echo -en \\033[1;32m"
	SETCOLOR_FAILURE="echo -en \\033[1;31m"
	SETCOLOR_WARNING="echo -en \\033[1;33m"
	SETCOLOR_NORMAL="echo -en \E[0m"
	echo -n "$2" && $MOVE_TO_COL
	echo -n "["
	if [ $1 = "success" -o $1 = "0" ] ;then ${SETCOLOR_SUCCESS}
		echo -n $"  OK  "
	elif [ $1 = "failure" -o $1 = "1" ] ;then ${SETCOLOR_FAILURE}
		echo -n $"FAILED"
	else 
		${SETCOLOR_WARNING}
		echo -n $"WARNING"
	fi
	${SETCOLOR_NORMAL}
	echo -n "]"
	echo
}

# --- 最佳实践：全局变量和常量使用全大写 ---

# --- 配置项 (全局常量) ---
readonly DLEGER_PORT="9878"
readonly NAMESRV_PORT="9876"

# --- 配置项 (自定义安装目录) ---
readonly ROCKETMQ_BASE_DIR="$HOME"

# --- 全局变量声明 ---
# 这些变量将在函数间共享
declare -a ALL_CLUSTER_IPS   # 新增：保存所有输入的IP，用于本机识别
declare -a CLUSTER_IPS       # 修改：用于生成配置的IP列表（可能是N-1个节点）
declare GLOBAL_CONTROLLER_DLEGER_PEERS
declare GLOBAL_CONTROLLER_ADDR
declare NODE_NAME
declare NETWORK_SEGMENT
declare GLOBAL_NAMESRV_ADDR
declare NEW_NAMESRV_ADDR

# --- 辅助函数 ---

# 1. 获取本机完整IP地址
get_local_ip() {
    local main_interface ip_addr
    main_interface=$(ip route show default 2>/dev/null | awk '/default/ {print $5}' | head -n1)
    if [ -z "$main_interface" ]; then return 1; fi
    ip_addr=$(ip addr show "$main_interface" 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -n1)
    if [ -z "$ip_addr" ]; then return 1; fi
    echo "$ip_addr"
    return 0
}

# 2. 获取本机IP的前两位网段
get_network_segment() {
    local main_interface ip_addr network_segment
    main_interface=$(ip route show default 2>/dev/null | awk '/default/ {print $5}' | head -n1)
    if [ -z "$main_interface" ]; then echo ""; return 1; fi
    ip_addr=$(ip addr show "$main_interface" 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -n1)
    if [ -z "$ip_addr" ]; then echo ""; return 1; fi
    network_segment=$(echo "$ip_addr" | cut -d'.' -f1-2)
    echo "$network_segment"
    return 0
}

# 3. 获取所有IP列表 (修改为填充 ALL_CLUSTER_IPS)
get_cluster_ips() {
    local ip_string valid=true
    declare -n ip_array_ref=$1 # 将引用 ALL_CLUSTER_IPS

    # 检测网段并赋值给全局变量 NETWORK_SEGMENT
    NETWORK_SEGMENT=$(get_network_segment)
    if [ $? -eq 0 ] && [ -n "$NETWORK_SEGMENT" ]; then
        echo "提示：检测到本机网段为 ${NETWORK_SEGMENT}.x.x，请输入该网段下的完整IP列表。"
    else
        echo "提示：未能自动检测网段，请手动输入完整的IP列表。"
    fi

    while true; do
        read -p "$(echo -e "\e[40;36m请输入集群所有IP，以逗号(,)分隔(使用Ctrl + Backspace键删除输入信息):\e[0m")" ip_string
        
        if [ -z "$ip_string" ]; then
            echo "错误：输入不能为空，请重新输入。"
            continue
        fi

        IFS=',' read -r -a ip_array_ref <<< "$ip_string"
        
        valid=true
        for ip in "${ip_array_ref[@]}"; do
            if ! [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
                echo "错误: '$ip' 不是一个有效的IP地址格式，请重新输入。"
                valid=false
                break
            fi
        done

        if [ "$valid" = true ]; then
            echo "成功解析到 ${#ip_array_ref[@]} 个IP地址。"
            return 0
        fi
    done
}

# 4. 生成 IP:PORT;... 格式的通用函数
build_ip_port_list() {
    local port=$1; shift; local ips=("$@"); local addr_array=()
    for ip in "${ips[@]}"; do addr_array+=("${ip}:${port}"); done
    IFS=';'; echo "${addr_array[*]}"; unset IFS
}

# --- 核心函数：收集所有信息并设置全局变量 (已重构) ---
prepare_global_variables() {
    echo "--- RocketMQ 全局配置生成器 v11.0 (分离配置与识别逻辑版) ---"
    
    # 步骤1: 获取所有IP，并存入 ALL_CLUSTER_IPS
    get_cluster_ips ALL_CLUSTER_IPS
    
    # 步骤2: (核心逻辑) 根据奇偶性决定 CLUSTER_IPS 的内容
    local total_nodes=${#ALL_CLUSTER_IPS[@]}
    if (( total_nodes % 2 == 0 )); then
        echo "检测到节点总数为偶数 ($total_nodes)，NameServer配置将使用前 $((total_nodes - 1)) 个节点。"
        # 创建 CLUSTER_IPS 作为 ALL_CLUSTER_IPS 的一个切片（不包括最后一个元素）
        CLUSTER_IPS=("${ALL_CLUSTER_IPS[@]:0:$((total_nodes - 1))}")
    else
        echo "检测到节点总数为奇数 ($total_nodes)，NameServer配置将使用所有节点。"
        # CLUSTER_IPS 是 ALL_CLUSTER_IPS 的一个副本
        CLUSTER_IPS=("${ALL_CLUSTER_IPS[@]}")
    fi
    echo "------------------------------------"
    
    # 步骤3: 识别本机节点名 (使用完整的 ALL_CLUSTER_IPS)
    local detected_ip local_ip
    detected_ip=$(get_local_ip)
    if [ $? -eq 0 ] && [ -n "$detected_ip" ]; then
        read -p "$(echo -e "\e[40;36m检测到本机IP为 $detected_ip，是否正确？[Y/n]:\e[0m")" confirm
        if [[ "$confirm" =~ ^[Yy]*$ ]] || [ -z "$confirm" ]; then
            local_ip="$detected_ip"
        else
            read -p "$(echo -e "\e[40;36m请手动输入本机IP:\e[0m")" local_ip
        fi
    else
        echo "未能自动检测本机IP。"
        read -p "$(echo -e "\e[40;36m请手动输入本机IP:\e[0m")" local_ip
    fi

    if ! [[ "$local_ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
        echo "错误：输入的IP '$local_ip' 格式无效，脚本终止。"
        exit 1
    fi

    # 关键改动：在完整的 ALL_CLUSTER_IPS 列表中查找本机IP
    for i in "${!ALL_CLUSTER_IPS[@]}"; do
        if [ "${ALL_CLUSTER_IPS[$i]}" = "$local_ip" ]; then
            NODE_NAME="n$i"
            echo "本机 ($local_ip) 在集群中的节点名为: $NODE_NAME"
            break
        fi
    done

    if [ -z "$NODE_NAME" ]; then
        echo "------------------------------------"
        echo "警告：本机IP '$local_ip' 不在您输入的集群IP列表中。脚本终止。"
        exit 1
    fi

    # 步骤4: 生成所有节点共享的配置 (使用可能被修改的 CLUSTER_IPS)
    echo "正在基于最终节点列表生成全局共享配置参数..."
    
    # 4.1 生成 controllerDLegerPeers (基于 CLUSTER_IPS)
    local -a peer_array=()
    for i in "${!CLUSTER_IPS[@]}"; do
        local ip="${CLUSTER_IPS[$i]}"
        local node_name="n$i"
        peer_array+=("${node_name}-${ip}:${DLEGER_PORT}")
    done
    IFS=';'
    GLOBAL_CONTROLLER_DLEGER_PEERS="${peer_array[*]}"
    unset IFS

    # 4.2 生成全局 namesrvAddr 和 controllerAddr (基于 CLUSTER_IPS)
    GLOBAL_NAMESRV_ADDR=$(build_ip_port_list "$NAMESRV_PORT" "${CLUSTER_IPS[@]}")
    GLOBAL_CONTROLLER_ADDR=$(build_ip_port_list "$DLEGER_PORT" "${CLUSTER_IPS[@]}")
    NEW_NAMESRV_ADDR=${GLOBAL_NAMESRV_ADDR//;/ }
    
    echo "所有全局变量已准备完毕。"
}

# --- 安装函数 (保持不变) ---

install_rocketmq () {
	color 0 "开始安装rocketmq"
    cd $ROCKETMQ_BASE_DIR/
	wget https://dist.apache.org/repos/dist/release/rocketmq/5.3.0/rocketmq-all-5.3.0-bin-release.zip && color 0 "rocketmq下载成功！"
	unzip -q rocketmq-all-5.3.0-bin-release.zip 
	mv $ROCKETMQ_BASE_DIR/rocketmq-all-5.3.0-bin-release $ROCKETMQ_BASE_DIR/rocketmq
	mkdir -p $ROCKETMQ_BASE_DIR/rocketmq/logs
	mkdir -p $ROCKETMQ_BASE_DIR/rocketmq/conf/acl
	sed -i "s#\${user.home}#$ROCKETMQ_BASE_DIR/rocketmq#g" $ROCKETMQ_BASE_DIR/rocketmq/conf/*.xml
	color 0 "安装rocketmq完成"
}

install_namesrv () {
	color 0 "开始配置rocketmq_namesrv"
	tee $ROCKETMQ_BASE_DIR/rocketmq/conf/namesrv.conf <<-EOF
listenPort=9876
enableControllerInNamesrv=true
controllerDLegerGroup=group1
controllerDLegerPeers=$GLOBAL_CONTROLLER_DLEGER_PEERS
controllerDLegerSelfId=$NODE_NAME
controllerStorePath=$ROCKETMQ_BASE_DIR/rocketmq/controller/DledgerController
enableElectUncleanMaster=true
notifyBrokerRoleChanged=true
EOF
	color 0 "配置rocketmq_namesrv完成"
}

install_broker () {
	color 0 "开始配置rocketmq_broker"
	tee $ROCKETMQ_BASE_DIR/rocketmq/conf/broker.conf <<-EOF
#所属集群名字
brokerClusterName=rocketmq-control-cluster
#broker名字，注意此处不同的配置文件填写的不一样
brokerName=broker-a
#0 表示 Master，>0 表示 Slave
#brokerId=0
brokerId=-1
brokerRole=SLAVE
#brokerIP1=172.16.250.213
#nameServer地址，分号分割
fetchNameSrvAddrByDnsLookup=false
namesrvAddr=$GLOBAL_NAMESRV_ADDR
#在发送消息时，自动创建服务器不存在的topic，默认创建的队列数
defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic，建议线下开启，线上关闭
autoCreateTopicEnable=false
#是否允许 Broker 自动创建订阅组，建议线下开启，线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口，10911为默认值
listenPort=10911
#表示Master监听Slave请求的端口,默认为服务端口+1
haListenPort=10912
#删除文件时间点，默认凌晨 4点
deleteWhen=04
#文件保留时间，默认 48 小时
fileReservedTime=48
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条，根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=$ROCKETMQ_BASE_DIR/rocketmq/store
#commitLog 存储路径
storePathCommitLog=$ROCKETMQ_BASE_DIR/rocketmq/store/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=$ROCKETMQ_BASE_DIR/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=$ROCKETMQ_BASE_DIR/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=$ROCKETMQ_BASE_DIR/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=$ROCKETMQ_BASE_DIR/rocketmq/store/abort
#限制的消息大小
maxMessageSize=104857600
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker 的角色
#- ASYNC_MASTER  异步复制Master
#- SYNC_MASTER  同步双写Master
#- SLAVE
#brokerRole=ASYNC_MASTER
#刷盘方式
#- ASYNC_FLUSH  异步刷盘
#- SYNC_FLUSH  同步刷盘
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
sendMessageThreadPoolNums=64
#拉消息线程池数量
pullMessageThreadPoolNums=128
#broker检测队列中的消息等待时间（默认是200毫秒，自行配置）
waitTimeMillsInSendQueue=10000
#发送队列线程容量
sendThreadPoolQueueCapacity=100000
#关闭堆外内存
transientStorePoolEnable=false
#关闭文件预热
warmMapedFileEnable=false
#开启堆内传
transferMsgByHeap=true
aclEnable=false

# https://rocketmq.apache.org/zh/docs/deploymentOperations/03autofailover#broker-部署
# Broker controller 模式的总开关，只有该值为 true，自动主从切换模式才会打开
enableControllerMode=true
fetchControllerAddrByDnsLookup=false
controllerAddr=$GLOBAL_CONTROLLER_ADDR
# 向 controller 同步 Broker 副本信息的时间间隔
syncBrokerMetadataPeriod=5000
# 检查 SyncStateSet 的时间间隔，检查 SyncStateSet 可能会 shrink SyncState
checkSyncStateSetPeriod=5000
# 同步 controller 元数据的时间间隔，主要是获取 active controller 的地址
syncControllerMetadataPeriod=10000
EOF
	color 0 "配置rocketmq_broker完成"
}

install_rmq-proxy () {
	color 0 "开始配置rocketmq_rmq-proxy"
tee $ROCKETMQ_BASE_DIR/rocketmq/conf/rmq-proxy.json <<-EOF
{
  "namesrvAddr": "$GLOBAL_NAMESRV_ADDR",
  "proxyMode": "cluster",
  "rocketMQClusterName": "rocketmq-control-cluster",
  "remotingListenPort": 8380,
  "grpcServerPort": 8081,
  "useEndpointPortFromRequest": true,
  "enableACL": false
}
EOF
	color 0 "配置rocketmq_rmq-proxy完成"
}

install_plain_acl () {
	color 0 "开始配置rocketmq_plain_acl"
	tee $ROCKETMQ_BASE_DIR/rocketmq/conf/acl/plain_acl.yml <<-EOF
globalWhiteRemoteAddresses:
- ${NETWORK_SEGMENT}.*.*
accounts:
- accessKey: cqtcqtcqt
  secretKey: cqt!010@Rocketmq
  admin: true
  defaultTopicPerm: DENY
  defaultGroupPerm: SUB
  groupPerms:
  - cloudcc_business=PUB|SUB
  topicPerms:
  - cloudcc=PUB|SUB
- accessKey: cqtcloudcc
  secretKey: cqt@2020
  admin: true
  defaultTopicPerm: PUB|SUB
  defaultGroupPerm: PUB|SUB
  topicPerms:
  - cloudcc=PUB|SUB
  groupPerms:
  - cloudcc_business=PUB|SUB
dataVersion:
- counter: 28
  timestamp: 1698148186380
EOF
	color 0 "配置rocketmq_plain_acl完成"
}

# 定义一个函数，用于显示 RocketMQ 常用操作指南
show_rocketmq_quick_guide() {
    # 定义颜色变量，方便统一修改
    local YELLOW='\e[1;33m'
    local GREEN='\e[1;32m'
    local RESET='\e[0m'
    
    echo " "
    echo -e "${GREEN}常用操作会存到:${RESET}${YELLOW}$ROCKETMQ_BASE_DIR/rocketmq_quick_guide.txt${RESET}"
    echo "-------------------------------------------------"
    echo -e "${YELLOW}# 停止namesrv${RESET}"
    echo "sh $ROCKETMQ_BASE_DIR/rocketmq/bin/mqshutdown namesrv"
    echo -e "${YELLOW}# 启动namesrv${RESET}"
    echo "nohup sh $ROCKETMQ_BASE_DIR/rocketmq/bin/mqnamesrv  -c $ROCKETMQ_BASE_DIR/rocketmq/conf/namesrv.conf > $ROCKETMQ_BASE_DIR/rocketmq/logs/mqnamesrv.log 2>&1 &"
    echo "-------------------------------------------------"
    echo -e "${YELLOW}# 停止broker${RESET}"
    echo "sh $ROCKETMQ_BASE_DIR/rocketmq/bin/mqshutdown broker"
    echo -e "${YELLOW}# 启动broker${RESET}"
    echo "nohup sh $ROCKETMQ_BASE_DIR/rocketmq/bin/mqbroker -c $ROCKETMQ_BASE_DIR/rocketmq/conf/broker.conf -pc $ROCKETMQ_BASE_DIR/rocketmq/conf/rmq-proxy.json --enable-proxy > $ROCKETMQ_BASE_DIR/rocketmq/logs/broker.log 2>&1 &"
    echo "-------------------------------------------------"
    echo -e "${YELLOW}查看集群状态：${RESET}"
    echo "sh $ROCKETMQ_BASE_DIR/rocketmq/bin/mqadmin clusterlist -n $NEW_NAMESRV_ADDR"
    echo "-------------------------------------------------"
    echo -e "${YELLOW}可以使用命令快捷创建Topic：${RESET}"
    echo "sh $ROCKETMQ_BASE_DIR/rocketmq/bin/mqadmin updateTopic -n '$GLOBAL_NAMESRV_ADDR' -c rocketmq-control-cluster -t base_ext_exchange -r 8 -w 8 -o true"
}

# 定义一个函数，用于显示需要手动修改的 RocketMQ 配置
configure_rocketmq_memory() {
    # 定义颜色变量
    local YELLOW='\e[1;33m'
    local GREEN='\e[1;32m'
    local RED='\e[1;31m'
    local RESET='\e[0m'

    echo " "
    echo "-------------------------------------------------"
    echo -e "${RED}注意：${RESET}${GREEN}需要根据机器配置修改以下两个参数${RESET}${YELLOW}(以下命令使用在机器内存为8G时)${RESET}"
    echo "sed -i 's#-Xms8g -Xmx8g#-Xms4g -Xmx4g#g' $ROCKETMQ_BASE_DIR/rocketmq/bin/runbroker.sh"
    echo "sed -i 's#-Xms4g -Xmx4g#-Xms1g -Xmx1g#g' $ROCKETMQ_BASE_DIR/rocketmq/bin/runserver.sh"
    echo "-------------------------------------------------"
    echo -e "${RED}注意：${RESET}${GREEN}需要手动修改每个节点${RESET}${YELLOW}$ROCKETMQ_BASE_DIR/rocketmq/conf/broker.conf${GREEN}文件中的${RESET}${YELLOW}brokerName${GREEN}参数${RESET}"
}

# --- 主执行流程 ---
# 1. 先准备好所有全局变量
prepare_global_variables

# 2. 然后依次执行安装和配置，这些函数会直接使用已设置好的全局变量
install_rocketmq
install_namesrv
install_broker
install_rmq-proxy
install_plain_acl

#3.显示rocketmq常用命令
show_rocketmq_quick_guide | tee rocketmq_quick_guide.txt

#3.显示rocketmq需要手动修改的配置
configure_rocketmq_memory