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

ENV_FILE="${FT_ENV_FILE:-/etc/fasttunnel/fasttunnel.env}"
STATE_DIR="${FT_STATE_DIR:-/var/lib/fasttunnel}"
SYSCTL_FILE="/etc/sysctl.d/99-fasttunnel.conf"

log() { printf '[FIRSTBOOT] %s\n' "$*" >&2; }

mkdir -p "$STATE_DIR" "$(dirname "$ENV_FILE")"
chmod 700 "$STATE_DIR"

# Create a sane config if an old/minimal package left none behind.
if [[ ! -f "$ENV_FILE" ]]; then
    cat >"$ENV_FILE" <<'EOC'
FT_NODE=auto
FT_PEER_NODE=2
FT_LOCAL=auto
FT_NETWORK=10.77.0.0/16
FT_TUN=ft0
FT_LISTEN=30002
FT_CONTROL=31002
FT_TLS_PORT=30002
FT_NETWORK_ID=0
FT_PIN=0
FT_SEED=0
FT_EXIT=1
FT_COORD=1
FT_LEARN_PEER=1
FT_PEER=mtoolls.org:30002
FT_TRANSPORT=auto
FT_IDENTITY_FILE=/etc/fasttunnel/node.key
FT_SHAPER=privacy
FT_FORWARD=auto
FT_MASQUERADE=auto
FT_FIREWALL_BACKEND=auto
FT_EXT_IF=auto
FT_IPV6=auto
EOC
    chmod 0644 "$ENV_FILE"
fi

set_env() {
    local key="$1" value="$2"
    if grep -qE "^${key}=" "$ENV_FILE"; then
        sed -i "s|^${key}=.*|${key}=${value}|" "$ENV_FILE"
    else
        printf '%s=%s\n' "$key" "$value" >>"$ENV_FILE"
    fi
}

# Read current settings. The file is controlled by root and uses KEY=value syntax.
set -a
# shellcheck disable=SC1090
source "$ENV_FILE"
set +a

# Stable per-machine identity. Keep generated values in /var/lib so upgrades never change them.
if [[ "${FT_NODE:-auto}" == "auto" || -z "${FT_NODE:-}" ]]; then
    if [[ -s "$STATE_DIR/node.id" ]]; then
        node_id="$(cat "$STATE_DIR/node.id")"
    else
        seed="$(cat /etc/machine-id 2>/dev/null || hostname)"
        hex="$(printf '%s' "$seed" | sha256sum | awk '{print substr($1,1,8)}')"
        node_id=$((16#$hex))
        (( node_id == 0 )) && node_id=3
        (( node_id == 2 )) && node_id=3
        printf '%u\n' "$node_id" >"$STATE_DIR/node.id"
        chmod 0600 "$STATE_DIR/node.id"
    fi
    set_env FT_NODE "$node_id"
    FT_NODE="$node_id"
    log "generated stable node id=$FT_NODE"
fi

# Generate a stable IPv4 address inside 10.77.0.0/16 when FT_LOCAL=auto.
# Two hash-derived host octets give 64k-ish space; .0/.1/.255 are avoided.
if [[ "${FT_LOCAL:-auto}" == "auto" || -z "${FT_LOCAL:-}" ]]; then
    if [[ -s "$STATE_DIR/overlay.ip" ]]; then
        overlay_ip="$(cat "$STATE_DIR/overlay.ip")"
    else
        n="$FT_NODE"
        oct3=$(( (n >> 8) & 255 ))
        oct4=$(( n & 255 ))
        (( oct3 == 0 )) && oct3=1
        (( oct4 < 3 )) && oct4=$((oct4 + 3))
        (( oct4 == 255 )) && oct4=254
        overlay_ip="10.77.${oct3}.${oct4}"
        # Do not accidentally claim the fixed bootstrap node address.
        [[ "$overlay_ip" == "10.77.0.2" ]] && overlay_ip="10.77.0.3"
        printf '%s\n' "$overlay_ip" >"$STATE_DIR/overlay.ip"
        chmod 0600 "$STATE_DIR/overlay.ip"
    fi
    set_env FT_LOCAL "$overlay_ip"
    FT_LOCAL="$overlay_ip"
    log "generated stable overlay IPv4=$FT_LOCAL"
fi

# Persist kernel settings needed by an EXIT/relay. IPv6 enable is best-effort because
# some VPS/container providers block it in the host kernel.
cat >"$SYSCTL_FILE" <<'EOS'
# Managed by FastTunnel. Does not touch firewall policy.
net.ipv4.ip_forward = 1
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.all.forwarding = 1
EOS

sysctl -q -w net.ipv4.ip_forward=1 || true
sysctl -q -w net.ipv6.conf.all.disable_ipv6=0 || log "IPv6 all.enable rejected by host; daemon may continue IPv4-only"
sysctl -q -w net.ipv6.conf.default.disable_ipv6=0 || log "IPv6 default.enable rejected by host; daemon may continue IPv4-only"
sysctl -q -w net.ipv6.conf.all.forwarding=1 || log "IPv6 forwarding rejected by host; daemon may continue IPv4-only"

log "ready node=$FT_NODE overlay=$FT_LOCAL peer=${FT_PEER:-none}"
