#!/bin/sh
set -eu

SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
APP_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
CONFIG_PATH=${1:-"$APP_DIR/router_local.conf"}

if [ ! -r "$CONFIG_PATH" ]; then
  echo "[router-local] config not found: $CONFIG_PATH" >&2
  exit 1
fi

# shellcheck disable=SC1090
. "$CONFIG_PATH"

CFST_WORK_DIR=${CFST_WORK_DIR:-"$APP_DIR/cfst"}
CFST_BIN=${CFST_BIN:-"./cfst"}
CFST_IP_FILE=${CFST_IP_FILE:-"ip.txt"}
CFST_RESULT_FILE=${CFST_RESULT_FILE:-"result.csv"}
CFST_DISPLAY_COUNT=${CFST_DISPLAY_COUNT:-10}
CFST_THREADS=${CFST_THREADS:-}
CFST_TEST_COUNT=${CFST_TEST_COUNT:-}
CFST_DOWNLOAD_COUNT=${CFST_DOWNLOAD_COUNT:-}
CFST_DOWNLOAD_TIME=${CFST_DOWNLOAD_TIME:-}
CFST_PORT=${CFST_PORT:-443}
CFST_URL=${CFST_URL:-}
CFST_HTTPING=${CFST_HTTPING:-0}
CFST_HTTPING_CODE=${CFST_HTTPING_CODE:-}
CFST_CFCOLO=${CFST_CFCOLO:-}
CFST_LATENCY_LIMIT=${CFST_LATENCY_LIMIT:-}
CFST_LATENCY_LOWER=${CFST_LATENCY_LOWER:-}
CFST_LOSS_LIMIT=${CFST_LOSS_LIMIT:-}
CFST_SPEED_LIMIT=${CFST_SPEED_LIMIT:-}
CFST_DISABLE_DOWNLOAD=${CFST_DISABLE_DOWNLOAD:-0}
CFST_ALL_IP=${CFST_ALL_IP:-0}
CFST_DEBUG=${CFST_DEBUG:-0}
CFST_SKIP_RUN=${CFST_SKIP_RUN:-0}

TOP_N=${TOP_N:-3}
RUNTIME_DIR=${RUNTIME_DIR:-"$APP_DIR/cfip_runtime"}
VALUE_TEXT_FILE=${VALUE_TEXT_FILE:-"current_ip.txt"}
VALUE_JSON_FILE=${VALUE_JSON_FILE:-"current_ip.json"}
STATE_FILE=${STATE_FILE:-"state.json"}
EXPORT_VARS_FILE=${EXPORT_VARS_FILE:-"substore_vars.json"}
VALUE_JSON_KEY=${VALUE_JSON_KEY:-ip}
STATE_LAST_GOOD_KEY=${STATE_LAST_GOOD_KEY:-last_good_ip}
EXPORT_VALUE_KEY=${EXPORT_VALUE_KEY:-AUTO_CFIP}

CURRENT_TEXT_PATH="$RUNTIME_DIR/$VALUE_TEXT_FILE"
CURRENT_JSON_PATH="$RUNTIME_DIR/$VALUE_JSON_FILE"
STATE_PATH="$RUNTIME_DIR/$STATE_FILE"
EXPORT_VARS_PATH="$RUNTIME_DIR/$EXPORT_VARS_FILE"
INDEX_PATH="$RUNTIME_DIR/index.html"
RESULT_PATH="$CFST_WORK_DIR/$CFST_RESULT_FILE"
UPDATED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

mkdir -p "$RUNTIME_DIR"

json_get_string() {
  key="$1"
  file="$2"
  if [ ! -f "$file" ]; then
    return 0
  fi
  sed -n "s/.*\"$key\":[[:space:]]*\"\([^\"]*\)\".*/\1/p" "$file" | head -n 1
}

json_escape() {
  printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
}

trim_cr() {
  printf '%s' "$1" | tr -d '\r'
}

build_top_candidates_json() {
  awk -F',' -v top_n="$TOP_N" '
    function trim(v) {
      gsub(/\r/, "", v)
      sub(/^[[:space:]]+/, "", v)
      sub(/[[:space:]]+$/, "", v)
      return v
    }
    function esc(v) {
      gsub(/\\/,"\\\\",v)
      gsub(/"/,"\\\"",v)
      return v
    }
    NR == 1 { next }
    count >= top_n { exit }
    NF < 1 { next }
    {
      ip = esc(trim($1))
      sent = esc(trim($2))
      received = esc(trim($3))
      loss = esc(trim($4))
      latency = esc(trim($5))
      speed = esc(trim($6))
      region = esc(trim($7))
      if (count > 0) {
        printf(",")
      }
      printf("{\"ip\":\"%s\",\"domain\":\"%s\",\"sent\":\"%s\",\"received\":\"%s\",\"loss_rate\":\"%s\",\"avg_latency\":\"%s\",\"download_speed\":\"%s\",\"region\":\"%s\"}", ip, ip, sent, received, loss, latency, speed, region)
      count++
    }
    END {
      if (count == 0) {
        printf("")
      }
    }
  ' "$RESULT_PATH"
}

write_text_value() {
  selected_ip="$1"
  printf '%s\n' "$selected_ip" > "$CURRENT_TEXT_PATH"
  rm -f "$INDEX_PATH"
  cp "$CURRENT_TEXT_PATH" "$INDEX_PATH"
}

write_success_outputs() {
  selected_ip="$1"
  top_candidates_json="$2"
  source_count="$3"

  escaped_ip=$(json_escape "$selected_ip")
  write_text_value "$selected_ip"
  cat > "$CURRENT_JSON_PATH" <<EOF
{
  "$VALUE_JSON_KEY": "$escaped_ip",
  "updated_at": "$UPDATED_AT",
  "status": "ok",
  "source_type": "cfst_local_busybox",
  "source_count": $source_count,
  "checked_count": 0,
  "top_candidates": [${top_candidates_json}]
}
EOF

  cat > "$STATE_PATH" <<EOF
{
  "updated_at": "$UPDATED_AT",
  "$STATE_LAST_GOOD_KEY": "$escaped_ip",
  "status": "ok",
  "source_count": $source_count,
  "checked_count": 0,
  "source_type": "cfst_local_busybox"
}
EOF

  cat > "$EXPORT_VARS_PATH" <<EOF
{
  "$EXPORT_VALUE_KEY": "$escaped_ip",
  "UPDATED_AT": "$UPDATED_AT",
  "STATUS": "ok"
}
EOF
}

write_error_with_fallback() {
  last_good_ip="$1"
  error_message="$2"
  escaped_ip=$(json_escape "$last_good_ip")
  escaped_error=$(json_escape "$error_message")

  write_text_value "$last_good_ip"
  cat > "$CURRENT_JSON_PATH" <<EOF
{
  "$VALUE_JSON_KEY": "$escaped_ip",
  "updated_at": "$UPDATED_AT",
  "status": "error_use_last_good",
  "error": "$escaped_error",
  "source_type": "cfst_local_busybox"
}
EOF

  cat > "$STATE_PATH" <<EOF
{
  "updated_at": "$UPDATED_AT",
  "$STATE_LAST_GOOD_KEY": "$escaped_ip",
  "status": "error",
  "error": "$escaped_error",
  "source_type": "cfst_local_busybox"
}
EOF

  cat > "$EXPORT_VARS_PATH" <<EOF
{
  "$EXPORT_VALUE_KEY": "$escaped_ip",
  "UPDATED_AT": "$UPDATED_AT",
  "STATUS": "error_use_last_good"
}
EOF
}

run_cfst() (
  cd "$CFST_WORK_DIR"
  set -- "$CFST_BIN" -f "$CFST_IP_FILE" -o "$CFST_RESULT_FILE" -p "$CFST_DISPLAY_COUNT" -tp "$CFST_PORT"

  if [ -n "$CFST_THREADS" ]; then
    set -- "$@" -n "$CFST_THREADS"
  fi
  if [ -n "$CFST_TEST_COUNT" ]; then
    set -- "$@" -t "$CFST_TEST_COUNT"
  fi
  if [ -n "$CFST_DOWNLOAD_COUNT" ]; then
    set -- "$@" -dn "$CFST_DOWNLOAD_COUNT"
  fi
  if [ -n "$CFST_DOWNLOAD_TIME" ]; then
    set -- "$@" -dt "$CFST_DOWNLOAD_TIME"
  fi
  if [ -n "$CFST_URL" ]; then
    set -- "$@" -url "$CFST_URL"
  fi
  if [ "$CFST_HTTPING" = "1" ]; then
    set -- "$@" -httping
  fi
  if [ -n "$CFST_HTTPING_CODE" ]; then
    set -- "$@" -httping-code "$CFST_HTTPING_CODE"
  fi
  if [ -n "$CFST_CFCOLO" ]; then
    set -- "$@" -cfcolo "$CFST_CFCOLO"
  fi
  if [ -n "$CFST_LATENCY_LIMIT" ]; then
    set -- "$@" -tl "$CFST_LATENCY_LIMIT"
  fi
  if [ -n "$CFST_LATENCY_LOWER" ]; then
    set -- "$@" -tll "$CFST_LATENCY_LOWER"
  fi
  if [ -n "$CFST_LOSS_LIMIT" ]; then
    set -- "$@" -tlr "$CFST_LOSS_LIMIT"
  fi
  if [ -n "$CFST_SPEED_LIMIT" ]; then
    set -- "$@" -sl "$CFST_SPEED_LIMIT"
  fi
  if [ "$CFST_DISABLE_DOWNLOAD" = "1" ]; then
    set -- "$@" -dd
  fi
  if [ "$CFST_ALL_IP" = "1" ]; then
    set -- "$@" -allip
  fi
  if [ "$CFST_DEBUG" = "1" ]; then
    set -- "$@" -debug
  fi

  "$@"
)

LAST_GOOD_IP=$(json_get_string "$STATE_LAST_GOOD_KEY" "$STATE_PATH")

if [ "$CFST_SKIP_RUN" != "1" ]; then
  if ! run_cfst; then
    if [ -n "$LAST_GOOD_IP" ]; then
      write_error_with_fallback "$LAST_GOOD_IP" "cfst run failed"
      echo "[router-local] cfst run failed, fallback to last good ip: $LAST_GOOD_IP"
      exit 0
    fi
    echo "[router-local] cfst run failed and no last good ip available" >&2
    exit 1
  fi
fi

if [ ! -s "$RESULT_PATH" ]; then
  if [ -n "$LAST_GOOD_IP" ]; then
    write_error_with_fallback "$LAST_GOOD_IP" "cfst result file missing or empty"
    echo "[router-local] empty result, fallback to last good ip: $LAST_GOOD_IP"
    exit 0
  fi
  echo "[router-local] result file missing or empty: $RESULT_PATH" >&2
  exit 1
fi

BEST_LINE=$(sed -n '2p' "$RESULT_PATH" | tr -d '\r')
BEST_IP=$(printf '%s' "$BEST_LINE" | cut -d',' -f1 | tr -d ' ')
SOURCE_COUNT=$(awk -F',' 'NR > 1 && NF > 0 { count++ } END { print count + 0 }' "$RESULT_PATH")
TOP_CANDIDATES_JSON=$(build_top_candidates_json)

if [ -z "$BEST_IP" ]; then
  if [ -n "$LAST_GOOD_IP" ]; then
    write_error_with_fallback "$LAST_GOOD_IP" "no valid ip found in cfst result"
    echo "[router-local] no valid ip found, fallback to last good ip: $LAST_GOOD_IP"
    exit 0
  fi
  echo "[router-local] no valid ip found in result file" >&2
  exit 1
fi

write_success_outputs "$BEST_IP" "$TOP_CANDIDATES_JSON" "$SOURCE_COUNT"
echo "[router-local] selected ip: $BEST_IP"
