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

CONF="/etc/blocklist-sync.conf"
if [[ ! -f "$CONF" ]]; then echo "Missing $CONF"; exit 1; fi
# Load conf (allow empty vars during source to avoid 'unbound variable' if values contain $)
set +u; source "$CONF"; set -u

mkdir -p "$STATE_DIR"
JSON_CUR="$STATE_DIR/blocklist.json"
JSON_NEW="$STATE_DIR/blocklist.new.json"
NFT_FILE="$STATE_DIR/blocklist.nft"

log(){ logger -t "$LOG_TAG" -- "$*"; echo "$LOG_TAG: $*"; }

# 1) Download central JSON
HTTP_CODE=$(curl -fsS -w "%{http_code}" -o "$JSON_NEW" "$API_URL" || true)
if [[ "$HTTP_CODE" != "200" ]]; then
  log "Fetch failed (HTTP $HTTP_CODE), keeping old list"
  exit 0
fi

# 2) Validate JSON
jq -e 'has("ver") and has("v4") and has("v6") and (.v4|type=="array") and (.v6|type=="array")' "$JSON_NEW" >/dev/null || {
  log "Invalid JSON schema, abort"; exit 1; }

# 3) Generate nft config
cat > "$NFT_FILE" <<EOF
table $NFT_TABLE {
    set $NFT_SET_V4 {
        type ipv4_addr
        flags interval
        elements = { $(jq -r '.v4[]?' "$JSON_NEW" | paste -sd", " -) }
    }
    set $NFT_SET_V6 {
        type ipv6_addr
        flags interval
        elements = { $(jq -r '.v6[]?' "$JSON_NEW" | paste -sd", " -) }
    }
    chain input {
        type filter hook input priority -10;
        ip saddr @$NFT_SET_V4 drop
        ip6 saddr @$NFT_SET_V6 drop
    }
}
EOF

# 4) Ensure table exists and apply
if ! nft list table $NFT_TABLE >/dev/null 2>&1; then
  log "Creating table $NFT_TABLE"
  nft -f <(echo "table $NFT_TABLE {}")
fi
nft -f "$NFT_FILE"

mv "$JSON_NEW" "$JSON_CUR"
log "Applied blocklist: v$(jq -r '.ver' "$JSON_CUR") v4=$(jq -r '.v4|length' "$JSON_CUR") v6=$(jq -r '.v6|length' "$JSON_CUR")"

# ---- RDNS operator matching (optional) ----
glob_to_regex() {
  local pat="$1"
  pat="${pat//\./\\.}"; pat="${pat//\*/.*}"
  echo "^${pat}$"
}
collect_candidate_ips() {
  local tmp="$STATE_DIR/rdns_candidates.txt"
  : > "$tmp"
  if [[ "${RDNS_SCAN_SOCKETS:-false}" == "true" ]]; then
    ss -ntu 2>/dev/null | awk 'NR>1 {split($5,a,":"); print a[1]}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' >> "$tmp" || true
    ss -ntu 2>/dev/null | awk 'NR>1 {print $5}' | grep -E '^\[.*\]:' | sed -E 's/^\[(.*)\]:.*/\1/' >> "$tmp" || true
  fi
  if [[ "${RDNS_SCAN_LOGS:-false}" == "true" ]]; then
    for f in ${LOG_PATHS}; do
      [[ -f "$f" ]] || continue
      tail -n "${LOG_TAIL_LINES:-200}" "$f" | \
        grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}|\b([0-9a-fA-F:]+:+)+[0-9a-fA-F]+\b' >> "$tmp" || true
    done
  fi
  sort -u "$tmp" -o "$tmp"; echo "$tmp"
}
ptr_lookup_ip() {
  local ip="$1"
  local cmd="${RDNS_DNS_CMD//%IP%/$ip}"
  timeout "${RDNS_TIMEOUT:-1}" bash -c "$cmd" 2>/dev/null | head -n1 | tr -d '\r' | sed 's/\.$//'
}

if [[ "${RDNS_ENABLE:-false}" == "true" ]]; then
  PAT_JSON="$STATE_DIR/rdns_patterns.json"
  curl -fsS -o "$PAT_JSON" "${RDNS_PATTERNS_URL}" || true
  if jq -e '.patterns|type=="array"' "$PAT_JSON" >/dev/null 2>&1; then
    mapfile -t PATTERNS < <(jq -r '.patterns[]' "$PAT_JSON" | sed '/^[[:space:]]*$/d')
  else
    PATTERNS=()
  fi
  if [[ ${#PATTERNS[@]} -gt 0 ]]; then
    CAND=$(collect_candidate_ips)
    CACHE="$STATE_DIR/rdns_cache.tsv"; touch "$CACHE"
    REGEXES=(); for p in "${PATTERNS[@]}"; do REGEXES+=( "$(glob_to_regex "$p")" ); done
    HIT_V4=(); HIT_V6=()
    count=0
    while IFS= read -r ip; do
      [[ -n "$ip" ]] || continue
      if grep -qx "$ip" <(jq -r '.v4[]?' "$JSON_CUR" 2>/dev/null); then continue; fi
      if grep -qx "$ip" <(jq -r '.v6[]?' "$JSON_CUR" 2>/dev/null); then continue; fi
      ptr=$(awk -F'\t' -v IP="$ip" '$1==IP{print $2}' "$CACHE" | head -n1)
      if [[ -z "$ptr" ]]; then
        ptr=$(ptr_lookup_ip "$ip")
        echo -e "${ip}\t${ptr}\t$(date +%s)" >> "$CACHE"
      fi
      for rx in "${REGEXES[@]}"; do
        if [[ -n "$ptr" && "$ptr" =~ $rx ]]; then
          if [[ "$ip" =~ : ]]; then HIT_V6+=("$ip"); else HIT_V4+=("$ip"); fi
          break
        fi
      done
      ((count++)); [[ $count -ge ${RDNS_MAX_LOOKUPS:-200} ]] && break
    done < "$CAND"

    LOC_V4="$STATE_DIR/rdns_local_v4.txt"; LOC_V6="$STATE_DIR/rdns_local_v6.txt"
    touch "$LOC_V4" "$LOC_V6"
    if [[ ${#HIT_V4[@]} -gt 0 ]]; then
      printf "%s\n" "${HIT_V4[@]}" | sort -u >> "$LOC_V4"; sort -u "$LOC_V4" -o "$LOC_V4"
      nft add element "$NFT_TABLE" "$NFT_SET_V4" { $(paste -sd, "$LOC_V4") } 2>/dev/null || true
    fi
    if [[ ${#HIT_V6[@]} -gt 0 ]]; then
      printf "%s\n" "${HIT_V6[@]}" | sort -u >> "$LOC_V6"; sort -u "$LOC_V6" -o "$LOC_V6"
      nft add element "$NFT_TABLE" "$NFT_SET_V6" { $(paste -sd, "$LOC_V6") } 2>/dev/null || true
    fi

    if [[ "${RDNS_AUTO_REPORT:-false}" == "true" ]]; then
      for ip in "${HIT_V4[@]}" "${HIT_V6[@]}"; do
        ptr=$(awk -F'\t' -v IP="$ip" '$1==IP{print $2}' "$CACHE" | head -n1)
        curl -fsS -X POST -d "ip=$ip&note=rdns:${ptr}" "${RDNS_REPORT_URL}" >/dev/null || true
      done
    fi
  fi
fi
