#!/usr/bin/env bash
# scripts/phase-04-network-create.sh
#
# Phase-04 Step 4.1: create the Neutron external provider network + FIP subnet
# (provider-ext / provider-ext-fip). Encapsulates the do-doc create block AS A SCRIPT
# (D-056): consequential + MUTATING but fully IDEMPOTENT and self-gating -- the human
# gates by choosing to invoke it; re-running is safe (skip-if-exists). Pair the
# read-only phase-04-network-verify.sh before (PRE gate) and after (POST/EXIT gate).
#
# DOCFIX-047: the provider gateway is discovered BY CIDR (lib-net PATTERN-1), never via
# the do-doc's hardcoded `maas admin subnet read 1`.
#
# Tunables via env (D-003 defaults): EXT_NET EXT_SUBNET PHYSNET FIP_START FIP_END
# Requires: jumphost; jq; admin-openrc sourced (OS_AUTH_URL); openstack + the 'admin' MAAS profile.
# Usage:  source ~/admin-openrc && scripts/phase-04-network-create.sh
# Exit:   0 created or already-present (gate confirmed) | 1 gate/confirm fail | 2 precondition
# ASCII + LF.

set -euo pipefail
shopt -s inherit_errexit 2>/dev/null || true

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=scripts/lib-net.sh
. "$SCRIPT_DIR/lib-net.sh"

PROVIDER_CIDR="10.12.4.0/22"               # provider-public plane
GW_EXPECT="${PLANE_GW[$PROVIDER_CIDR]}"     # 10.12.4.1 -- pinned
EXT_NET="${EXT_NET:-provider-ext}"
EXT_SUBNET="${EXT_SUBNET:-provider-ext-fip}"
PHYSNET="${PHYSNET:-physnet1}"
EXT_CIDR="${EXT_CIDR:-$PROVIDER_CIDR}"
FIP_START="${FIP_START:-10.12.5.0}"
FIP_END="${FIP_END:-10.12.7.254}"

need_jq || exit 2
command -v openstack >/dev/null 2>&1 || { echo "FAIL: openstack client not found" >&2; exit 2; }
command -v maas      >/dev/null 2>&1 || { echo "FAIL: maas client not found" >&2; exit 2; }
[ -n "${OS_AUTH_URL:-}" ] || { echo "FAIL: OS_AUTH_URL unset -- 'source ~/admin-openrc' first" >&2; exit 2; }

# DOCFIX-047: provider gateway by CIDR (never 'maas admin subnet read 1')
GW=$(maas admin subnets read 2>/dev/null | jq -r --arg c "$PROVIDER_CIDR" '.[] | select(.cidr==$c) | .gateway_ip')
[ "$GW" = "$GW_EXPECT" ] || { echo "GATE FAIL: MAAS provider gateway='$GW' (expected $GW_EXPECT, by CIDR $PROVIDER_CIDR)"; exit 1; }
echo "[OK] gateway $GW (discovered by CIDR $PROVIDER_CIDR)"

if openstack network show "$EXT_NET" -f value -c id >/dev/null 2>&1; then
  echo "[SKIP] network $EXT_NET exists"
else
  openstack network create --external --provider-network-type flat \
    --provider-physical-network "$PHYSNET" "$EXT_NET" -f value -c id
  openstack network set --tag role=provider "$EXT_NET"
  echo "[OK] network $EXT_NET created + tagged"
fi

if openstack subnet show "$EXT_SUBNET" -f value -c id >/dev/null 2>&1; then
  echo "[SKIP] subnet $EXT_SUBNET exists"
else
  openstack subnet create --network "$EXT_NET" --subnet-range "$EXT_CIDR" \
    --gateway "$GW" --no-dhcp --allocation-pool start="$FIP_START",end="$FIP_END" \
    "$EXT_SUBNET" -f value -c id
  openstack subnet set --tag role=provider --tag "netbox-iprange=${FIP_START}-${FIP_END}" "$EXT_SUBNET"
  echo "[OK] subnet $EXT_SUBNET created + tagged"
fi

echo "=== CONFIRM ==="
EXT_OK=$(openstack network show "$EXT_NET" -f json | jq -r 'if (."router:external"==true and ."provider:network_type"=="flat" and ."provider:physical_network"=="'"$PHYSNET"'" and .shared==false) then "true" else "false" end')
openstack network show "$EXT_NET" -f json | jq -c '{name, external: ."router:external", type: ."provider:network_type", physnet: ."provider:physical_network", shared, tags}'
openstack subnet  show "$EXT_SUBNET" -f json | jq -c '{name, cidr, gateway_ip, enable_dhcp, allocation_pools, tags}'
[ "$EXT_OK" = "true" ] || { echo "CONFIRM FAIL: $EXT_NET attributes not external/flat/$PHYSNET/not-shared"; exit 1; }
echo "[OK] $EXT_NET + $EXT_SUBNET present and correct -- phase-04 create complete"
