#!/bin/sh

CONF="cf-optimizer"
RUN_DIR="/tmp/run/cf-optimizer"
TMP_DIR="/tmp/cf-optimizer"
HOSTS_FILE="/tmp/hosts/cf-optimizer"
LOG_FILE="/var/log/cf-optimizer.log"
DEFAULT_IPS_FILE="/usr/share/cf-optimizer/default_ips.txt"
COLO_MAP_FILE="/usr/share/cf-optimizer/colo_map.json"
PID_FILE="$RUN_DIR/cf-optimizer.pid"
COLO_CACHE_FILE="$RUN_DIR/colo_cache.txt"
STATUS_JSON="$RUN_DIR/status.json"
CURRENT_IP_FILE="$RUN_DIR/current_ip.txt"
PRIMARY_IP_FILE="$RUN_DIR/primary_ip.txt"
STANDBY_IP_FILE="$RUN_DIR/standby_ip.txt"
BASELINE_TCP_FILE="$RUN_DIR/baseline_tcp.txt"
FAIL_STREAK_FILE="$RUN_DIR/fail_streak.txt"

log() {
	local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
	echo "$msg"
	mkdir -p "$(dirname "$LOG_FILE")"
	echo "$msg" >> "$LOG_FILE"
	# 限制日志大小不超过 1000 行
	if [ -f "$LOG_FILE" ] && [ $(wc -l < "$LOG_FILE") -gt 1500 ]; then
		tail -n 800 "$LOG_FILE" > "$LOG_FILE.tmp" && mv -f "$LOG_FILE.tmp" "$LOG_FILE"
	fi
}

get_colo_name() {
	local code="$1"
	if [ -f "$COLO_MAP_FILE" ] && [ -n "$code" ]; then
		local name
		name=$(grep -E "\"$code\"[[:space:]]*:" "$COLO_MAP_FILE" 2>/dev/null | head -n 1 | sed -E 's/.*:[[:space:]]*"([^"]+)".*/\1/')
		if [ -n "$name" ]; then
			echo "$name"
			return
		fi
	fi
	echo "${code:-未知}"
}

update_colo_cache() {
	local ip="$1"
	local colo="$2"
	[ -z "$ip" ] || [ -z "$colo" ] && return
	mkdir -p "$RUN_DIR"
	touch "$COLO_CACHE_FILE"
	grep -v "^$ip[[:space:]]" "$COLO_CACHE_FILE" > "$COLO_CACHE_FILE.tmp" 2>/dev/null
	echo "$ip $colo" >> "$COLO_CACHE_FILE.tmp"
	mv -f "$COLO_CACHE_FILE.tmp" "$COLO_CACHE_FILE"
}

get_cached_colo() {
	local ip="$1"
	[ ! -f "$COLO_CACHE_FILE" ] && return
	grep "^$ip[[:space:]]" "$COLO_CACHE_FILE" 2>/dev/null | tail -n 1 | awk '{print $2}'
}

clean_hosts() {
	mkdir -p "$RUN_DIR"
	if [ -f "$HOSTS_FILE" ]; then
		rm -f "$HOSTS_FILE"
		killall -HUP dnsmasq 2>/dev/null
		log "已清空优选 hosts 映射并重载 dnsmasq"
	fi
	rm -f "$CURRENT_IP_FILE" "$PRIMARY_IP_FILE" "$STANDBY_IP_FILE" "$BASELINE_TCP_FILE" "$FAIL_STREAK_FILE"
	rm -rf "$RUN_DIR/task.lock"
	cat <<EOF > "$STATUS_JSON"
{
  "running": false,
  "last_update": "",
  "best_ip": "",
  "best_colo": "",
  "best_tcp_lat": 0,
  "best_tls_lat": 0,
  "standby_ip": "",
  "standby_colo": "",
  "standby_tcp_lat": 0,
  "watchdog_status": "未运行",
  "domains": [],
  "rankings": []
}
EOF
}

sync_hosts() {
	. /lib/functions.sh
	config_load "$CONF"
	local enabled
	config_get_bool enabled settings enabled 0
	if [ "$enabled" != "1" ]; then
		clean_hosts
		return 0
	fi

	local domains=""
	append_sync_domain() {
		local d="$1"
		[ -n "$d" ] && domains="$domains $d"
	}
	config_list_foreach settings domains append_sync_domain

	if [ -z "$domains" ]; then
		clean_hosts
		return 0
	fi

	local current_ip=""
	[ -f "$CURRENT_IP_FILE" ] && current_ip=$(cat "$CURRENT_IP_FILE" 2>/dev/null)

	if [ -z "$current_ip" ]; then
		local cand_tmp="$TMP_DIR/cand_init.txt"
		mkdir -p "$TMP_DIR"
		load_candidate_ips "$cand_tmp"
		current_ip=$(head -n 1 "$cand_tmp" 2>/dev/null)
		rm -f "$cand_tmp"
	fi

	[ -z "$current_ip" ] && return 0

	local hosts_tmp="$HOSTS_FILE.tmp"
	mkdir -p "$(dirname "$HOSTS_FILE")"
	> "$hosts_tmp"
	echo "# Auto-generated by cf-optimizer sync on $(date '+%Y-%m-%d %H:%M:%S')" >> "$hosts_tmp"
	local d
	for d in $domains; do
		echo "$current_ip $d" >> "$hosts_tmp"
	done
	mv -f "$hosts_tmp" "$HOSTS_FILE"
	killall -HUP dnsmasq 2>/dev/null
	log "已即时同步域名配置至 hosts 并重载 dnsmasq (定向至: $current_ip)"
}

load_candidate_ips() {
	local out_file="$1"
	> "$out_file"

	local ip_source
	config_get ip_source settings ip_source "builtin"

	if [ "$ip_source" = "builtin" ] || [ "$ip_source" = "mixed" ]; then
		if [ -f "$DEFAULT_IPS_FILE" ]; then
			grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' "$DEFAULT_IPS_FILE" >> "$out_file"
		fi
	fi

	if [ "$ip_source" = "custom" ] || [ "$ip_source" = "mixed" ]; then
		append_custom_ip() {
			local _item="$1"
			local _base_prefix _host
			[ -z "$_item" ] && return
			# 若为 CIDR 简单网段 (如 /24)，取前 3 个 IP
			case "$_item" in
				*/*)
					_base_prefix=$(echo "$_item" | cut -d'/' -f1 | cut -d'.' -f1-3)
					for _host in 1 2 3; do
						echo "$_base_prefix.$_host" >> "$out_file"
					done
					;;
				*)
					echo "$_item" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' >> "$out_file"
					;;
			esac
		}
		config_list_foreach settings custom_ips append_custom_ip
	fi

	# 兜底：若文件为空，填入稳定官方公共 IP
	if [ ! -s "$out_file" ]; then
		echo "104.16.0.1" >> "$out_file"
		echo "104.17.0.1" >> "$out_file"
		echo "104.18.0.1" >> "$out_file"
		echo "172.64.0.1" >> "$out_file"
	fi

	# 排序去重
	sort -u "$out_file" > "$out_file.tmp" && mv -f "$out_file.tmp" "$out_file"
}

# 粗筛单节点探测
probe_fast() {
	local ip="$1"
	local res_dir="$2"
	# 仅测 TCP 握手
	local connect_time
	connect_time=$(curl -s -k -o /dev/null --connect-timeout 1 -m 2 -w "%{time_connect}\n" \
		--resolve "speed.cloudflare.com:443:$ip" "https://speed.cloudflare.com/__down?bytes=0" 2>/dev/null)
	
	if [ $? -eq 0 ] && [ -n "$connect_time" ] && [ "$connect_time" != "0.000000" ]; then
		local ms=$(awk "BEGIN {printf \"%08.2f\", $connect_time * 1000}")
		echo "$ms $ip" > "$res_dir/$ip"
	fi
}

run_optimization() {
	. /lib/functions.sh
	config_load "$CONF"

	local enabled
	config_get_bool enabled settings enabled 0
	if [ "$enabled" != "1" ]; then
		log "服务未启用，退出任务"
		clean_hosts
		return 0
	fi

	local domains=""
	append_domain() {
		local d="$1"
		[ -n "$d" ] && domains="$domains $d"
	}
	config_list_foreach settings domains append_domain

	if [ -z "$domains" ]; then
		log "未配置目标加速域名，跳过优选"
		return 0
	fi

	local concurrency sample_count hysteresis_ms
	config_get concurrency settings concurrency 10
	config_get sample_count settings sample_count 4
	config_get hysteresis_ms settings hysteresis_ms 30

	local colo_filter_mode
	config_get colo_filter_mode settings colo_filter_mode "none"

	local target_colos=""
	append_target_colo() {
		local _item="$1"
		local _colo _clean_colo
		[ -z "$_item" ] && return
		for _colo in $_item; do
			_clean_colo=$(echo "$_colo" | tr 'a-z' 'A-Z' | tr -d ' \t\r\n')
			if [ -n "$_clean_colo" ]; then
				case " $target_colos " in
					*" $_clean_colo "*) ;;
					*) target_colos="$target_colos $_clean_colo" ;;
				esac
			fi
		done
	}
	if [ "$colo_filter_mode" != "none" ]; then
		local multi_colos=""
		config_get multi_colos settings colo_list ""
		[ -n "$multi_colos" ] && append_target_colo "$multi_colos"
		config_list_foreach settings colo_list append_target_colo
		config_list_foreach settings custom_colos append_target_colo
	fi

	check_colo_allowed() {
		local _colo="$1"
		[ -z "$_colo" ] && return 0
		[ "$colo_filter_mode" = "none" ] && return 0

		local _match=0
		local _tc
		for _tc in $target_colos; do
			if [ "$_tc" = "$_colo" ]; then
				_match=1
				break
			fi
		done

		if [ "$colo_filter_mode" = "exclude" ]; then
			[ "$_match" -eq 1 ] && return 1 || return 0
		elif [ "$colo_filter_mode" = "include" ]; then
			[ "$_match" -eq 1 ] && return 0 || return 1
		fi
		return 0
	}

	log "开始执行优选任务，加速域名数: $(echo $domains | wc -w)，机房策略: $colo_filter_mode${target_colos:+ ($target_colos)}"

	local lock_dir="$RUN_DIR/task.lock"
	if ! mkdir "$lock_dir" 2>/dev/null; then
		local lock_pid=""
		[ -f "$lock_dir/pid" ] && lock_pid=$(cat "$lock_dir/pid" 2>/dev/null)
		if [ -n "$lock_pid" ] && ! kill -0 "$lock_pid" 2>/dev/null; then
			log "检测到残留任务锁 (PID: $lock_pid 已退出)，自动释放死锁"
			rm -rf "$lock_dir"
			mkdir "$lock_dir" 2>/dev/null || return 0
		else
			log "已有优选任务正在运行中，跳过本次执行"
			return 0
		fi
	fi
	echo $$ > "$lock_dir/pid"

	mkdir -p "$TMP_DIR/fast" "$TMP_DIR/deep" "$RUN_DIR"
	rm -rf "$TMP_DIR/fast"/* "$TMP_DIR/deep"/*

	local cand_file="$TMP_DIR/candidates.txt"
	load_candidate_ips "$cand_file"
	local total_cands=$(wc -l < "$cand_file")
	log "阶段一：开始并发初筛，候选节点总数: $total_cands，并发度: $concurrency"

	# 并发初筛（采用 POSIX 批次等待机制，确保在任何非交互式 Shell 环境下严格限流）
	local running=0
	while read -r ip; do
		[ -z "$ip" ] && continue
		probe_fast "$ip" "$TMP_DIR/fast" &
		running=$((running + 1))
		if [ "$running" -ge "$concurrency" ]; then
			wait
			running=0
		fi
	done < "$cand_file"
	wait

	# 汇总初筛候选，结合机房缓存预先剔除黑名单机房
	local fast_sorted_file="$TMP_DIR/fast_sorted.txt"
	cat "$TMP_DIR/fast"/* 2>/dev/null | sort -n | head -n 30 > "$fast_sorted_file"

	local top_selected_file="$TMP_DIR/top_selected_ips.txt"
	> "$top_selected_file"
	local picked_count=0
	while read -r _lat ip; do
		[ -z "$ip" ] && continue
		local cached_colo=$(get_cached_colo "$ip")
		if [ -n "$cached_colo" ] && ! check_colo_allowed "$cached_colo"; then
			log "初筛预过滤: 节点 $ip ($cached_colo) 命中机房排除策略，自动略过"
			continue
		fi
		echo "$ip" >> "$top_selected_file"
		picked_count=$((picked_count + 1))
		[ "$picked_count" -ge 10 ] && break
	done < "$fast_sorted_file"

	local top_count=$(wc -l < "$top_selected_file")
	if [ "$top_count" -eq 0 ]; then
		log "阶段一初筛无可用候选节点（或全部被机房区域策略过滤），请检查配置"
		rm -rf "$TMP_DIR"
		rm -rf "$lock_dir"
		return 1
	fi

	local probe_domain=$(echo "$domains" | awk '{print $1}')
	[ -z "$probe_domain" ] && probe_domain="speed.cloudflare.com"

	log "阶段一初筛完成，选出 $top_count 个候选节点进入精测采样，探活域名: $probe_domain（每节点轮询交叉采样 $sample_count 轮）"

	# 阶段二：轮询交叉时序采样（跨越完整测试时段，精准捕获阶段性丢包与网络毛刺）
	mkdir -p "$TMP_DIR/samples"

	local seq
	for seq in $(seq 1 "$sample_count"); do
		while read -r ip; do
			[ -z "$ip" ] && continue
			[ -f "$TMP_DIR/blocked_${ip}" ] && continue
			[ -f "$TMP_DIR/colo_excluded_${ip}" ] && continue

			local raw_header="$TMP_DIR/header_${ip}_${seq}.txt"
			local metrics
			metrics=$(curl -s -k -I -o /dev/null --connect-timeout 2 -m 3 \
				-A "Mozilla/5.0 (compatible; Cloudflare-Optimizer/1.0)" \
				--resolve "$probe_domain:443:$ip" "https://$probe_domain/" \
				-D "$raw_header" \
				-w "%{time_connect} %{time_appconnect} %{http_code}\n" 2>/dev/null)

			local tcp_sec=$(echo "$metrics" | awk '{print $1}')
			local tls_sec=$(echo "$metrics" | awk '{print $2}')
			local http_code=$(echo "$metrics" | awk '{print $3}')

			if [ "$http_code" = "403" ]; then
				touch "$TMP_DIR/blocked_${ip}"
				rm -f "$raw_header"
				continue
			fi

			local last_colo=""
			if [ -f "$raw_header" ]; then
				local cf_ray=$(grep -i '^cf-ray:' "$raw_header" 2>/dev/null | tr -d '\r\n')
				if [ -n "$cf_ray" ]; then
					last_colo=$(echo "$cf_ray" | sed -E 's/.*-([A-Za-z0-9]+).*/\1/' | tr 'a-z' 'A-Z')
				fi
				rm -f "$raw_header"
			fi

			if [ -n "$last_colo" ]; then
				update_colo_cache "$ip" "$last_colo"
				if ! check_colo_allowed "$last_colo"; then
					log "节点 $ip 机房 ($last_colo) 不符合区域过滤策略 ($colo_filter_mode)，已终止采样并排除"
					touch "$TMP_DIR/colo_excluded_${ip}"
					continue
				fi
			fi

			if [ -n "$http_code" ] && [ "$http_code" != "000" ] && [ -n "$tcp_sec" ] && [ "$tcp_sec" != "0.000000" ]; then
				local tcp_ms=$(awk "BEGIN {printf \"%.2f\", $tcp_sec * 1000}")
				local tls_ms=$(awk "BEGIN {printf \"%.2f\", $tls_sec * 1000}")
				echo "1|$tcp_ms|$tls_ms|$last_colo" >> "$TMP_DIR/samples/$ip"
			else
				echo "0|0|0|$last_colo" >> "$TMP_DIR/samples/$ip"
			fi
		done < "$top_selected_file"
	done

	# 汇总统计各节点采样指标
	while read -r ip; do
		[ -z "$ip" ] && continue
		if [ -f "$TMP_DIR/blocked_${ip}" ]; then
			log "节点 $ip 触发权限阻断 (HTTP 403/企业限制)，已自动排除"
			continue
		fi
		if [ -f "$TMP_DIR/colo_excluded_${ip}" ]; then
			continue
		fi

		local sample_file="$TMP_DIR/samples/$ip"
		[ ! -f "$sample_file" ] && continue

		local success_count=0
		local total_tcp=0
		local total_tls=0
		local min_tcp=99999
		local max_tcp=0
		local last_colo=""

		while IFS='|' read -r ok tcp_ms tls_ms colo; do
			[ -n "$colo" ] && last_colo="$colo"
			if [ "$ok" = "1" ]; then
				success_count=$((success_count + 1))
				total_tcp=$(awk "BEGIN {printf \"%.2f\", $total_tcp + $tcp_ms}")
				total_tls=$(awk "BEGIN {printf \"%.2f\", $total_tls + $tls_ms}")
				min_tcp=$(awk "BEGIN {if ($tcp_ms < $min_tcp) print $tcp_ms; else print $min_tcp}")
				max_tcp=$(awk "BEGIN {if ($tcp_ms > $max_tcp) print $tcp_ms; else print $max_tcp}")
			fi
		done < "$sample_file"

		if [ -z "$last_colo" ]; then
			last_colo=$(get_cached_colo "$ip")
		fi

		if ! check_colo_allowed "$last_colo"; then
			log "节点 $ip 机房 ($last_colo) 最终区域校验未通过，舍弃"
			continue
		fi

		local loss_rate=$(awk "BEGIN {printf \"%.1f\", (1 - $success_count / $sample_count) * 100}")
		if [ "$success_count" -gt 0 ]; then
			local avg_tcp=$(awk "BEGIN {printf \"%.2f\", $total_tcp / $success_count}")
			local avg_tls=$(awk "BEGIN {printf \"%.2f\", $total_tls / $success_count}")
			local jitter=$(awk "BEGIN {printf \"%.2f\", $max_tcp - $min_tcp}")
			# 综合评分：平均时延 + 抖动*0.5 + 丢包率*10（采用固定宽度 0 填充）
			local score=$(awk "BEGIN {printf \"%08.2f\", $avg_tcp + $jitter * 0.5 + $loss_rate * 10}")

			local colo_disp=$(get_colo_name "$last_colo")
			echo "$score|$ip|$avg_tcp|$min_tcp|$max_tcp|$avg_tls|$loss_rate%|$colo_disp|$last_colo" >> "$TMP_DIR/deep_results.txt"
		fi
	done < "$top_selected_file"

	if [ ! -s "$TMP_DIR/deep_results.txt" ]; then
		log "精测采样后无可用健康节点"
		rm -rf "$TMP_DIR"
		rm -rf "$lock_dir"
		return 1
	fi

	# 排序：按 score 从低到高数值排序
	sort -n "$TMP_DIR/deep_results.txt" > "$TMP_DIR/deep_sorted.txt"

	local best_line=$(head -n 1 "$TMP_DIR/deep_sorted.txt")
	local best_score=$(echo "$best_line" | cut -d'|' -f1)
	local best_ip=$(echo "$best_line" | cut -d'|' -f2)
	local best_avg_tcp=$(echo "$best_line" | cut -d'|' -f3)
	local best_min_tcp=$(echo "$best_line" | cut -d'|' -f4)
	local best_max_tcp=$(echo "$best_line" | cut -d'|' -f5)
	local best_avg_tls=$(echo "$best_line" | cut -d'|' -f6)
	local best_loss=$(echo "$best_line" | cut -d'|' -f7)
	local best_colo=$(echo "$best_line" | cut -d'|' -f8)

	log "测速完成，最优候选: $best_ip ($best_colo), 平均延迟: ${best_avg_tcp}ms, 丢包率: $best_loss"

	# 迟滞逻辑判断
	local current_ip=""
	[ -f "$CURRENT_IP_FILE" ] && current_ip=$(cat "$CURRENT_IP_FILE")

	local final_ip="$best_ip"
	local final_colo="$best_colo"
	local final_tcp="$best_avg_tcp"
	local final_tls="$best_avg_tls"

	if [ -n "$current_ip" ] && [ "$current_ip" != "$best_ip" ]; then
		local cur_info=$(grep "|$current_ip|" "$TMP_DIR/deep_sorted.txt" 2>/dev/null)
		local cur_colo_allowed=1
		local cur_cached_colo=$(get_cached_colo "$current_ip")
		if [ -n "$cur_cached_colo" ] && ! check_colo_allowed "$cur_cached_colo"; then
			cur_colo_allowed=0
		fi

		if [ -n "$cur_info" ] && [ "$cur_colo_allowed" -eq 1 ]; then
			local cur_tcp=$(echo "$cur_info" | cut -d'|' -f3)
			local cur_loss=$(echo "$cur_info" | cut -d'|' -f7)
			local cur_colo=$(echo "$cur_info" | cut -d'|' -f8)

			if [ "$cur_loss" = "0.0%" ]; then
				# 测算相比当前在用 IP 的绝对时延差 (ms)
				local diff_ms=$(awk "BEGIN {if ($cur_tcp > $best_avg_tcp) printf \"%.2f\", $cur_tcp - $best_avg_tcp; else print 0}")
				local is_better=$(awk "BEGIN {print ($diff_ms >= $hysteresis_ms) ? 1 : 0}")

				if [ "$is_better" -eq 0 ]; then
					log "新优选 IP 优化幅度 (${diff_ms}ms) 未达迟滞阈值 (${hysteresis_ms}ms)，保持当前在用 IP: $current_ip"
					final_ip="$current_ip"
					final_colo="$cur_colo"
					final_tcp="$cur_tcp"
					final_tls=$(echo "$cur_info" | cut -d'|' -f6)
				else
					log "新优选 IP 性能显著提升 (时延改善 ${diff_ms}ms >= ${hysteresis_ms}ms)，触发切换"
				fi
			else
				log "当前在用 IP 发生丢包 ($cur_loss)，强制切换至新最优 IP: $best_ip"
			fi
		else
			if [ "$cur_colo_allowed" -eq 0 ]; then
				log "当前在用 IP ($current_ip / $cur_cached_colo) 已被机房过滤策略排除，强制切换至新最优 IP: $best_ip"
			fi
		fi
	fi

	# 原子写入 /tmp/hosts/cf-optimizer
	local hosts_tmp="$HOSTS_FILE.tmp"
	mkdir -p "$(dirname "$HOSTS_FILE")"
	> "$hosts_tmp"
	echo "# Auto-generated by cf-optimizer on $(date '+%Y-%m-%d %H:%M:%S')" >> "$hosts_tmp"
	local d
	for d in $domains; do
		echo "$final_ip $d" >> "$hosts_tmp"
	done
	mv -f "$hosts_tmp" "$HOSTS_FILE"
	echo "$final_ip" > "$CURRENT_IP_FILE"
	echo "$final_ip" > "$PRIMARY_IP_FILE"
	echo "0" > "$FAIL_STREAK_FILE"

	# 选拔次优备选节点（排名紧随其后且 IP 不同的健康节点）
	local standby_ip=""
	local standby_colo="无备选"
	local standby_tcp="-"
	while IFS='|' read -r _sc _ip _atip _minip _maxip _attls _lrate _cdisp _craw; do
		if [ -n "$_ip" ] && [ "$_ip" != "$final_ip" ]; then
			standby_ip="$_ip"
			standby_colo="$_cdisp"
			standby_tcp="$_atip"
			break
		fi
	done < "$TMP_DIR/deep_sorted.txt"
	echo "$standby_ip|$standby_colo|$standby_tcp" > "$STANDBY_IP_FILE"
	echo "$final_tcp" > "$BASELINE_TCP_FILE"

	# 发送 HUP 信号通知 dnsmasq 毫秒级重载
	killall -HUP dnsmasq 2>/dev/null
	log "已更新 $HOSTS_FILE 并热重载 dnsmasq，在用主选: $final_ip ($final_colo)，次优备选: ${standby_ip:-无} ($standby_colo)"

	# 组装状态 JSON 给 LuCI 前端消费
	local now_str=$(date '+%Y-%m-%d %H:%M:%S')
	local domain_json="["
	local first_d=1
	for d in $domains; do
		[ "$first_d" -eq 0 ] && domain_json="$domain_json,"
		domain_json="$domain_json{\"domain\":\"$d\",\"ip\":\"$final_ip\",\"colo\":\"$final_colo\",\"tcp_lat\":\"$final_tcp ms\",\"tls_lat\":\"$final_tls ms\",\"status\":\"正常\"}"
		first_d=0
	done
	domain_json="$domain_json]"

	local rankings_json="["
	local first_r=1
	local rank_idx=1
	while IFS='|' read -r sc ip atip minip maxip attls lrate cdisp craw; do
		[ -z "$ip" ] && continue
		[ "$first_r" -eq 0 ] && rankings_json="$rankings_json,"
		rankings_json="$rankings_json{\"rank\":$rank_idx,\"ip\":\"$ip\",\"colo\":\"$cdisp\",\"avg_lat\":\"$atip ms\",\"lat_range\":\"$minip / $maxip ms\",\"loss_rate\":\"$lrate\"}"
		first_r=0
		rank_idx=$((rank_idx + 1))
		[ "$rank_idx" -gt 5 ] && break
	done < "$TMP_DIR/deep_sorted.txt"
	rankings_json="$rankings_json]"

	cat <<EOF > "$STATUS_JSON.tmp"
{
  "running": true,
  "last_update": "$now_str",
  "best_ip": "$final_ip",
  "best_colo": "$final_colo",
  "best_tcp_lat": "$final_tcp ms",
  "best_tls_lat": "$final_tls ms",
  "standby_ip": "$standby_ip",
  "standby_colo": "$standby_colo",
  "standby_tcp_lat": "$standby_tcp ms",
  "watchdog_status": "正常监控中",
  "domains": $domain_json,
  "rankings": $rankings_json
}
EOF
	mv -f "$STATUS_JSON.tmp" "$STATUS_JSON"
	rm -rf "$TMP_DIR"
	rm -rf "$lock_dir"
	return 0
}

apply_fast_failover() {
	local target_ip="$1"
	local target_colo="$2"
	local target_tcp="${3:--}"

	. /lib/functions.sh
	config_load "$CONF"
	local domains=""
	append_failover_domain() {
		local d="$1"
		[ -n "$d" ] && domains="$domains $d"
	}
	config_list_foreach settings domains append_failover_domain

	local hosts_tmp="$HOSTS_FILE.tmp"
	mkdir -p "$(dirname "$HOSTS_FILE")"
	> "$hosts_tmp"
	echo "# Auto-generated by cf-optimizer failover on $(date '+%Y-%m-%d %H:%M:%S')" >> "$hosts_tmp"
	local d
	for d in $domains; do
		echo "$target_ip $d" >> "$hosts_tmp"
	done
	mv -f "$hosts_tmp" "$HOSTS_FILE"
	echo "$target_ip" > "$CURRENT_IP_FILE"
	echo "" > "$STANDBY_IP_FILE"
	if [ -n "$target_tcp" ] && [ "$target_tcp" != "-" ]; then
		echo "$target_tcp" > "$BASELINE_TCP_FILE"
	else
		rm -f "$BASELINE_TCP_FILE"
	fi

	killall -HUP dnsmasq 2>/dev/null
	log "已将 hosts 紧急倒换至次优节点: $target_ip ($target_colo) 并重载 dnsmasq"

	if [ -f "$STATUS_JSON" ]; then
		local now_str=$(date '+%Y-%m-%d %H:%M:%S')
		local domain_json="["
		local first_d=1
		for d in $domains; do
			[ "$first_d" -eq 0 ] && domain_json="$domain_json,"
			domain_json="$domain_json{\"domain\":\"$d\",\"ip\":\"$target_ip\",\"colo\":\"$target_colo\",\"tcp_lat\":\"$target_tcp ms\",\"tls_lat\":\"-\",\"status\":\"已倒换\"}"
			first_d=0
		done
		domain_json="$domain_json]"

		local tmp_status="$STATUS_JSON.tmp"
		sed -E "s/\"best_ip\":[[:space:]]*\"[^\"]*\"/\"best_ip\": \"$target_ip\"/" "$STATUS_JSON" | \
		sed -E "s/\"best_colo\":[[:space:]]*\"[^\"]*\"/\"best_colo\": \"$target_colo\"/" | \
		sed -E "s/\"standby_ip\":[[:space:]]*\"[^\"]*\"/\"standby_ip\": \"\"/" | \
		sed -E "s/\"standby_colo\":[[:space:]]*\"[^\"]*\"/\"standby_colo\": \"已倒换转正\"/" | \
		sed -E "s/\"last_update\":[[:space:]]*\"[^\"]*\"/\"last_update\": \"$now_str (已触发倒换)\"/" | \
		sed -E "s/\"watchdog_status\":[[:space:]]*\"[^\"]*\"/\"watchdog_status\": \"已触发故障倒换\"/" | \
		sed -E "s/\"domains\":[[:space:]]*\[[^]]*\]/\"domains\": $domain_json/" > "$tmp_status" 2>/dev/null
		[ -s "$tmp_status" ] && mv -f "$tmp_status" "$STATUS_JSON"
	fi
}

check_health_and_failover() {
	[ ! -f "$CURRENT_IP_FILE" ] && return 0
	local current_ip=$(cat "$CURRENT_IP_FILE" 2>/dev/null)
	[ -z "$current_ip" ] && return 0

	. /lib/functions.sh
	config_load "$CONF"

	local failover_enabled fail_threshold latency_multiplier
	config_get_bool failover_enabled settings failover_enabled 1
	[ "$failover_enabled" != "1" ] && return 0
	config_get fail_threshold settings fail_threshold 2
	config_get latency_multiplier settings latency_multiplier "2.0"

	local domains=""
	append_check_domain() {
		local d="$1"
		[ -n "$d" ] && domains="$domains $d"
	}
	config_list_foreach settings domains append_check_domain
	local probe_domain=$(echo "$domains" | awk '{print $1}')
	[ -z "$probe_domain" ] && probe_domain="speed.cloudflare.com"

	local metrics
	metrics=$(curl -s -k -I -o /dev/null --connect-timeout 2 -m 3 \
		-A "Mozilla/5.0 (compatible; Cloudflare-Optimizer/1.0)" \
		--resolve "$probe_domain:443:$current_ip" "https://$probe_domain/" \
		-w "%{time_connect} %{http_code}\n" 2>/dev/null)

	local tcp_sec=$(echo "$metrics" | awk '{print $1}')
	local http_code=$(echo "$metrics" | awk '{print $2}')
	local cur_tcp_ms=0
	if [ -n "$tcp_sec" ] && [ "$tcp_sec" != "0.000000" ]; then
		cur_tcp_ms=$(awk "BEGIN {printf \"%.2f\", $tcp_sec * 1000}")
	fi

	local baseline_tcp=0
	[ -f "$BASELINE_TCP_FILE" ] && baseline_tcp=$(cat "$BASELINE_TCP_FILE" 2>/dev/null)
	baseline_tcp=${baseline_tcp:-0}

	local streak=0
	[ -f "$FAIL_STREAK_FILE" ] && streak=$(cat "$FAIL_STREAK_FILE" 2>/dev/null)
	streak=${streak:-0}

	local is_abnormal=0
	local abnormal_reason=""

	if [ -z "$http_code" ] || [ "$http_code" = "000" ] || [ "$http_code" = "403" ]; then
		is_abnormal=1
		abnormal_reason="HTTP ${http_code:-000} 阻断或超时"
	elif [ "$latency_multiplier" != "0" ] && [ "$latency_multiplier" != "0.0" ]; then
		local is_degraded
		is_degraded=$(awk "BEGIN {
			if ($baseline_tcp > 0 && $cur_tcp_ms >= ($baseline_tcp * $latency_multiplier) && ($cur_tcp_ms - $baseline_tcp) >= 50)
				print 1;
			else
				print 0;
		}")
		if [ "$is_degraded" -eq 1 ]; then
			is_abnormal=1
			abnormal_reason="延迟严重劣化 (${cur_tcp_ms}ms >= 基线 ${baseline_tcp}ms x ${latency_multiplier})"
		fi
	fi

	if [ "$is_abnormal" -eq 0 ]; then
		if [ "$streak" -gt 0 ]; then
			log "主用优选节点 $current_ip 探活恢复正常 (HTTP $http_code, TCP ${cur_tcp_ms}ms)"
			echo "0" > "$FAIL_STREAK_FILE"
		fi
		return 0
	fi

	streak=$((streak + 1))
	echo "$streak" > "$FAIL_STREAK_FILE"
	log "在用优选节点 $current_ip 探活异常 [$abnormal_reason]，连续异常: $streak/$fail_threshold"

	if [ "$streak" -ge "$fail_threshold" ]; then
		echo "0" > "$FAIL_STREAK_FILE"
		local standby_info=""
		[ -f "$STANDBY_IP_FILE" ] && standby_info=$(cat "$STANDBY_IP_FILE" 2>/dev/null)
		local standby_ip=$(echo "$standby_info" | cut -d'|' -f1)
		local standby_colo=$(echo "$standby_info" | cut -d'|' -f2)

		if [ -n "$standby_ip" ] && [ "$standby_ip" != "$current_ip" ]; then
			log "正在核验次优备选节点健康度: $standby_ip ($standby_colo)"
			local s_metrics
			s_metrics=$(curl -s -k -I -o /dev/null --connect-timeout 2 -m 3 \
				-A "Mozilla/5.0 (compatible; Cloudflare-Optimizer/1.0)" \
				--resolve "$probe_domain:443:$standby_ip" "https://$probe_domain/" \
				-w "%{time_connect} %{http_code}\n" 2>/dev/null)
			local s_tcp_sec=$(echo "$s_metrics" | awk '{print $1}')
			local s_code=$(echo "$s_metrics" | awk '{print $2}')
			local s_tcp_ms="-"
			[ -n "$s_tcp_sec" ] && [ "$s_tcp_sec" != "0.000000" ] && s_tcp_ms=$(awk "BEGIN {printf \"%.2f\", $s_tcp_sec * 1000}")

			if [ -n "$s_code" ] && [ "$s_code" != "000" ] && [ "$s_code" != "403" ]; then
				log "主用节点异常，次优备选节点验证健康 (HTTP $s_code, TCP ${s_tcp_ms}ms)，秒级倒换至次优节点"
				apply_fast_failover "$standby_ip" "$standby_colo" "$s_tcp_ms"
				return 0
			else
				log "次优备选节点同样不可用 (HTTP ${s_code:-000})，提前拉起全网节点紧急重测"
			fi
		else
			log "未配置次优备选节点，提前拉起全网节点紧急重测"
		fi

		run_optimization
	fi
}

daemon_loop() {
	mkdir -p "$RUN_DIR"
	echo $$ > "$PID_FILE"
	trap 'rm -f "$PID_FILE"; [ -f "$RUN_DIR/task.lock/pid" ] && [ "$(cat "$RUN_DIR/task.lock/pid" 2>/dev/null)" = "$$" ] && rm -rf "$RUN_DIR/task.lock"; exit 0' INT TERM EXIT

	log "守护进程启动 [PID: $$]"

	local last_full_run=0

	while true; do
		. /lib/functions.sh
		config_load "$CONF"

		local enabled
		config_get_bool enabled settings enabled 0
		if [ "$enabled" != "1" ]; then
			log "配置已禁用，清理并退出守护进程"
			clean_hosts
			break
		fi

		local interval failover_enabled health_interval
		config_get interval settings interval 120
		[ "$interval" -lt 10 ] && interval=10
		local full_interval_sec=$((interval * 60))

		config_get_bool failover_enabled settings failover_enabled 1
		config_get health_interval settings health_interval 60
		[ "$health_interval" -lt 15 ] && health_interval=15

		local now=$(date +%s)
		if [ "$last_full_run" -eq 0 ] || [ $((now - last_full_run)) -ge "$full_interval_sec" ]; then
			run_optimization
			last_full_run=$(date +%s)
		elif [ "$failover_enabled" = "1" ]; then
			check_health_and_failover
		fi

		local sleep_sec="$health_interval"
		if [ "$failover_enabled" != "1" ]; then
			sleep_sec=30
		fi

		local elapsed=0
		while [ "$elapsed" -lt "$sleep_sec" ]; do
			sleep 5 &
			wait $!
			elapsed=$((elapsed + 5))
		done
	done
}

case "$1" in
	run)
		run_optimization
		;;
	sync-hosts)
		sync_hosts
		;;
	daemon)
		daemon_loop
		;;
	clean)
		clean_hosts
		;;
	status)
		if [ -f "$STATUS_JSON" ]; then
			cat "$STATUS_JSON"
		else
			echo '{"running":false,"domains":[],"rankings":[]}'
		fi
		;;
	*)
		echo "用法: $0 {run|sync-hosts|daemon|clean|status}"
		exit 1
		;;
esac
