#!/usr/bin/env bash
set -euo pipefail

# 列出当前 Docker 与主机上已占用的 IPv4 网段，并给出一个不冲突的 /24 子网建议。
# 依赖：docker、ip、python3（使用标准库 ipaddress，不额外安装软件）

print_section() { echo; echo "==== $1 ===="; }

# 收集 Docker 网络的子网
collect_docker_cidrs() {
  docker network ls -q \
    | xargs -I {} docker network inspect -f '{{range .IPAM.Config}}{{.Subnet}} {{end}}' {} 2>/dev/null \
    | tr ' ' '\n' \
    | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+' \
    | sort -u || true
}

# 收集主机网卡上的 IPv4（转为 x.x.x.x/len 形式即可，由 Python 侧宽松解析 strict=False）
collect_host_addr_cidrs() {
  ip -4 addr show \
    | awk '/inet /{print $2}' \
    | sort -u || true
}

# 收集主机路由表中的 IPv4 CIDR
collect_host_route_cidrs() {
  ip -4 route \
    | awk '{print $1}' \
    | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+' \
    | sort -u || true
}

merge_unique() {
  # 将多段输入合并并去重（读取所有 stdin）
  sort -u
}

check_overlap_python() {
  # 读取 stdin 中的已占用 CIDR 列表，与参数中的候选 CIDR 比较是否重叠
  # 用法： existing_list | check_overlap_python 100.120.0.0/24
  python3 - "$1" <<'PY'
import sys, ipaddress

if len(sys.argv) < 2:
    print("MISSING_CANDIDATE", file=sys.stderr)
    sys.exit(2)

candidate = ipaddress.ip_network(sys.argv[1], strict=False)

for line in sys.stdin:
    s = line.strip()
    if not s:
        continue
    try:
        net = ipaddress.ip_network(s, strict=False)
    except Exception:
        # 忽略无法解析的行
        continue
    if candidate.overlaps(net):
        # 任一重叠则退出 1
        sys.exit(1)

# 无重叠
sys.exit(0)
PY
}

generate_candidates() {
  # 可通过环境变量 CANDIDATES 覆盖（以空格分隔的 CIDR 列表）
  if [[ -n "${CANDIDATES:-}" ]]; then
    for c in $CANDIDATES; do echo "$c"; done
    return 0
  fi

  # 默认候选集：优先给出一个常用、不与 RFC1918 大段重合的 /24
  echo "100.120.0.0/24"

  # 继续在 CGNAT 段（100.64.0.0/10）内按顺序穷举 /24（会尽快在前面命中便返回）
  for s in $(seq 64 127); do
    for t in $(seq 0 255); do
      echo "100.$s.$t.0/24"
    done
  done

  # 追加若干常见未用的 10.x/24
  for t in 200 201 202 203 210 211 212; do
    echo "10.$t.0.0/24"
  done
}

main() {
  print_section "Collect occupied subnets (Docker)"
  docker_cidrs=$(collect_docker_cidrs || true)
  if [[ -n "$docker_cidrs" ]]; then echo "$docker_cidrs"; else echo "<none>"; fi

  print_section "Collect occupied subnets (Host addresses)"
  host_addr_cidrs=$(collect_host_addr_cidrs || true)
  if [[ -n "$host_addr_cidrs" ]]; then echo "$host_addr_cidrs"; else echo "<none>"; fi

  print_section "Collect occupied subnets (Host routes)"
  host_route_cidrs=$(collect_host_route_cidrs || true)
  if [[ -n "$host_route_cidrs" ]]; then echo "$host_route_cidrs"; else echo "<none>"; fi

  print_section "Compute union of occupied subnets"
  occupied=$(printf "%s\n%s\n%s\n" "$docker_cidrs" "$host_addr_cidrs" "$host_route_cidrs" | merge_unique || true)
  if [[ -n "$occupied" ]]; then echo "$occupied"; else echo "<none>"; fi

  print_section "Find first free /24 candidate"
  while read -r cand; do
    if [[ -z "$cand" ]]; then continue; fi
    if echo "$occupied" | check_overlap_python "$cand"; then
      echo "Suggested free subnet: $cand"
      exit 0
    fi
  done < <(generate_candidates)

  echo "No free candidate found in current list. You can set CANDIDATES env to extend." >&2
  exit 1
}

main "$@"



