#!/usr/bin/env bash
# Remove every dedicated q4.suby.pl route without racing other Caddy writers.
set -euo pipefail

ADMIN="${Q4_CADDY_ADMIN:-http://10.6.0.105:2019}"
ROUTES="${ADMIN%/}/config/apps/http/servers/srv1/routes"
HOST=q4.suby.pl
LOCK_FILE="${Q4_CADDY_ROUTE_LOCK:-/run/q4-caddy-route.lock}"
MAX_CONFLICTS="${Q4_CADDY_REMOVE_MAX_CONFLICTS:-8}"
MAX_MUTATIONS="${Q4_CADDY_REMOVE_MAX_MUTATIONS:-64}"

if [[ ! "$MAX_CONFLICTS" =~ ^[1-9][0-9]*$ ]] \
    || [[ ! "$MAX_MUTATIONS" =~ ^[1-9][0-9]*$ ]]; then
  echo "caddy-route-remove: retry limits must be positive integers" >&2
  exit 64
fi

exec 9>"$LOCK_FILE"
if ! flock -w 20 9; then
  echo "caddy-route-remove: timed out waiting for the route lock" >&2
  exit 1
fi

work=$(mktemp -d)
trap 'rm -rf -- "$work"' EXIT
conflicts=0
removed=0

while :; do
  headers="$work/headers"
  routes_json="$work/routes.json"
  delete_body="$work/delete.body"

  if ! curl -fsS --max-time 5 -D "$headers" -o "$routes_json" "$ROUTES"; then
    echo "caddy-route-remove: cannot read the Caddy route table" >&2
    exit 1
  fi

  etag=''
  while IFS= read -r header; do
    header=${header%$'\r'}
    if [[ "${header,,}" == etag:* ]]; then
      etag=${header#*:}
      etag=${etag#"${etag%%[![:space:]]*}"}
      break
    fi
  done <"$headers"
  if [[ -z "$etag" ]]; then
    echo "caddy-route-remove: Caddy did not return an ETag" >&2
    exit 1
  fi

  route_index=$(python3 - "$routes_json" "$HOST" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as stream:
    routes = json.load(stream)
host = sys.argv[2]

if not isinstance(routes, list):
    raise SystemExit("caddy-route-remove: route table is not a JSON array")

dedicated = []
for index, route in enumerate(routes):
    if not isinstance(route, dict):
        continue
    matchers = route.get("match")
    if not isinstance(matchers, list) or not matchers:
        continue

    mentions_host = False
    dedicated_to_host = True
    for matcher in matchers:
        hosts = matcher.get("host") if isinstance(matcher, dict) else None
        if isinstance(hosts, list) and host in hosts:
            mentions_host = True
        if not isinstance(hosts, list) or not hosts or any(item != host for item in hosts):
            dedicated_to_host = False

    if mentions_host and not dedicated_to_host:
        raise SystemExit(
            f"caddy-route-remove: refusing to delete shared route at index {index}"
        )
    if mentions_host:
        dedicated.append(index)

if dedicated:
    print(dedicated[-1])
PY
  )

  if [[ -z "$route_index" ]]; then
    echo "caddy-route-remove: $HOST is absent (removed $removed route(s))"
    exit 0
  fi
  if [[ ! "$route_index" =~ ^[0-9]+$ ]]; then
    echo "caddy-route-remove: parser returned an invalid route index" >&2
    exit 1
  fi
  if ((removed >= MAX_MUTATIONS)); then
    echo "caddy-route-remove: too many matching routes; refusing local start" >&2
    exit 1
  fi

  if ! status=$(curl -sS --max-time 5 -o "$delete_body" -w '%{http_code}' \
      -X DELETE -H "If-Match: $etag" "$ROUTES/$route_index"); then
    echo "caddy-route-remove: route deletion request failed" >&2
    exit 1
  fi

  if [[ "$status" == 412 ]]; then
    conflicts=$((conflicts + 1))
    if ((conflicts >= MAX_CONFLICTS)); then
      echo "caddy-route-remove: route table kept changing; refusing local start" >&2
      exit 1
    fi
    sleep 0.05
    continue
  fi
  if [[ ! "$status" =~ ^2[0-9][0-9]$ ]]; then
    echo "caddy-route-remove: Caddy rejected route deletion with HTTP $status" >&2
    test ! -s "$delete_body" || cat "$delete_body" >&2
    exit 1
  fi

  conflicts=0
  removed=$((removed + 1))
done
