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

SERVICE_NAME="veloramesh-server"
EDGE_SERVICE_NAME="${VELORAMESH_EDGE_SERVICE_NAME:-veloramesh-edge}"
SERVICE_USER="${VELORAMESH_SERVICE_USER:-veloramesh}"
SERVICE_GROUP="${VELORAMESH_SERVICE_GROUP:-veloramesh}"
INSTALL_DIR="${VELORAMESH_INSTALL_DIR:-/opt/veloramesh}"
CONFIG_DIR="${VELORAMESH_CONFIG_DIR:-/etc/veloramesh}"
DATA_DIR="${VELORAMESH_DATA_DIR:-/var/lib/veloramesh}"
TLS_DIR="$CONFIG_DIR/tls"
ENV_FILE="$CONFIG_DIR/veloramesh.env"
TLS_CERT="$TLS_DIR/fullchain.pem"
TLS_KEY="$TLS_DIR/privkey.pem"
UNIT_FILE="/etc/systemd/system/$SERVICE_NAME.service"
EDGE_UNIT_FILE="/etc/systemd/system/$EDGE_SERVICE_NAME.service"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SOURCE_BINARY="$SCRIPT_DIR/veloramesh-server"
EDGE_SOURCE_BINARY="$SCRIPT_DIR/veloramesh-edge"
START_SERVICE=1
ROLE="${VELORAMESH_SERVER_ROLE:-all}"
EDGE_TICKET_KEY_SOURCE="${VELORAMESH_EDGE_TICKET_KEY_SOURCE:-}"
DEFAULT_API_BIND_ADDR=":2053"
DEFAULT_EDGE_BIND_ADDR=":3478"
DEFAULT_VIRTUAL_IPV4_CIDR="${VELORAMESH_DEFAULT_VIRTUAL_IPV4_CIDR:-10.253.0.0/16}"
API_BIND_ADDR="${VELORAMESH_API_BIND_ADDR:-$DEFAULT_API_BIND_ADDR}"
EDGE_BIND_ADDR="${VELORAMESH_EDGE_BIND_ADDR:-$DEFAULT_EDGE_BIND_ADDR}"
API_BIND_ADDR_EXPLICIT=0
EDGE_BIND_ADDR_EXPLICIT=0
DEFAULT_VIRTUAL_IPV4_CIDR_EXPLICIT=0
[ -n "${VELORAMESH_API_BIND_ADDR:-}" ] && API_BIND_ADDR_EXPLICIT=1
[ -n "${VELORAMESH_EDGE_BIND_ADDR:-}" ] && EDGE_BIND_ADDR_EXPLICIT=1
[ -n "${VELORAMESH_DEFAULT_VIRTUAL_IPV4_CIDR:-}" ] && DEFAULT_VIRTUAL_IPV4_CIDR_EXPLICIT=1

usage() {
    cat <<USAGE
Usage: sudo bash install-veloramesh-server.sh [options]

Options:
  --role <all|api|edge>  Install all-in-one, API-only, or edge-only role.
  --api-bind <addr>      Normalized API bind value for automation, for example :2053 or 127.0.0.1:2053.
  --edge-bind <addr>     Normalized edge UDP bind value for automation, for example :3478 or 0.0.0.0:3478.
  --default-virtual-ipv4-cidr <cidr>
                        Default network virtual IPv4 CIDR for API/admin network creation.
  --binary <path>       Install the API server binary from this path.
  --edge-binary <path>  Install the edge discovery binary from this path.
  --edge-ticket-key <path>
                        Copy an existing edge discovery ticket key into place.
  --no-start            Install files and systemd units, but do not start services.
  -h, --help            Show this help text.

Environment overrides:
  VELORAMESH_SERVICE_USER
  VELORAMESH_SERVICE_GROUP
  VELORAMESH_INSTALL_DIR
  VELORAMESH_CONFIG_DIR
  VELORAMESH_DATA_DIR
  VELORAMESH_API_BIND_ADDR
  VELORAMESH_EDGE_BIND_ADDR
  VELORAMESH_DEFAULT_VIRTUAL_IPV4_CIDR
USAGE
}

log() {
    printf '[veloramesh] %s\n' "$1" >&2
}

fail() {
    printf '[veloramesh] error: %s\n' "$1" >&2
    exit 1
}

need_command() {
    command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"
}

normalize_role() {
    case "$1" in
        all|all-in-one|api-edge|api+edge)
            printf 'all'
            ;;
        api|api-only)
            printf 'api'
            ;;
        edge|edge-only)
            printf 'edge'
            ;;
        *)
            fail "unknown role: $1"
            ;;
    esac
}

role_label() {
    case "$ROLE" in
        all) printf 'API and edge' ;;
        api) printf 'API only' ;;
        edge) printf 'edge only' ;;
    esac
}

ensure_safe_data_dir() {
    case "$DATA_DIR" in
        ""|"/"|"/etc"|"/opt"|"/var"|"/var/lib"|"/usr"|"/usr/local")
            fail "refusing unsafe data directory: $DATA_DIR"
            ;;
    esac
    case "$DATA_DIR" in
        *veloramesh*|*VeloraMesh*) ;;
        *) fail "refusing non-VeloraMesh data directory: $DATA_DIR" ;;
    esac
}

repair_data_permissions() {
    ensure_safe_data_dir
    chown -R "$SERVICE_USER:$SERVICE_GROUP" "$DATA_DIR"
    chmod 0750 "$DATA_DIR"
    find "$DATA_DIR" -type d -exec chmod 0750 {} +
    find "$DATA_DIR" -maxdepth 1 -type f \( -name 'veloramesh.db' -o -name 'veloramesh.db-wal' -o -name 'veloramesh.db-shm' -o -name 'membership-ticket.key' -o -name 'edge-ticket.key' \) -exec chmod 0640 {} +
}

run_edge_init_key() {
    local runner
    local remove_runner=0
    local status

    if [ "$INSTALL_EDGE" -eq 1 ]; then
        runner="$INSTALL_DIR/veloramesh-edge"
    else
        runner="$INSTALL_DIR/.veloramesh-edge-init-key"
        install -o root -g root -m 0755 "$EDGE_SOURCE_BINARY" "$runner"
        remove_runner=1
    fi

    if VELORAMESH_EDGE_BIND_ADDR="$EDGE_BIND_ADDR" \
        VELORAMESH_EDGE_TICKET_KEY_FILE="$DATA_DIR/edge-ticket.key" \
        "$runner" init-key >/dev/null; then
        if [ "$remove_runner" -eq 1 ]; then
            rm -f -- "$runner"
        fi
        return 0
    fi

    status=$?
    if [ "$remove_runner" -eq 1 ]; then
        rm -f -- "$runner"
    fi
    return "$status"
}

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

remove_env_values() {
    [ -f "$ENV_FILE" ] || return 0
    local key
    for key in "$@"; do
        sed -i "/^${key}=/d" "$ENV_FILE"
    done
}

read_env_value() {
    local wanted="$1"
    local key
    local value
    [ -f "$ENV_FILE" ] || return 0
    while IFS='=' read -r key value; do
        case "$key" in
            ""|\#*) continue ;;
        esac
        if [ "$key" = "$wanted" ]; then
            printf '%s' "$value"
            return 0
        fi
    done < "$ENV_FILE"
}

resolve_existing_listen_addrs() {
    local existing
    [ -f "$ENV_FILE" ] || return 0
    if [ "$API_BIND_ADDR_EXPLICIT" -eq 0 ]; then
        existing="$(read_env_value VELORAMESH_API_BIND_ADDR)"
        [ -n "$existing" ] && API_BIND_ADDR="$existing"
    fi
    if [ "$EDGE_BIND_ADDR_EXPLICIT" -eq 0 ]; then
        existing="$(read_env_value VELORAMESH_EDGE_BIND_ADDR)"
        [ -n "$existing" ] && EDGE_BIND_ADDR="$existing"
    fi
    if [ "$DEFAULT_VIRTUAL_IPV4_CIDR_EXPLICIT" -eq 0 ]; then
        existing="$(read_env_value VELORAMESH_DEFAULT_VIRTUAL_IPV4_CIDR)"
        [ -n "$existing" ] && DEFAULT_VIRTUAL_IPV4_CIDR="$existing"
    fi
}

is_ipv4_literal() {
    local value="$1"
    local a
    local b
    local c
    local d
    local extra
    IFS=. read -r a b c d extra <<< "$value"
    [ -z "${extra:-}" ] || return 1
    for octet in "$a" "$b" "$c" "$d"; do
        case "$octet" in
            ""|*[!0-9]*) return 1 ;;
        esac
        [ "$octet" -ge 0 ] && [ "$octet" -le 255 ] || return 1
    done
    return 0
}

validate_listen_addr() {
    local label="$1"
    local value="$2"
    local host
    local port
    [ -n "$value" ] || fail "$label listen address cannot be empty"
    case "$value" in
        *[[:space:]]*) fail "$label listen address cannot contain whitespace" ;;
        *://*|*/*|*\?*|*\#*) fail "$label listen address must be a local bind address, not a URL" ;;
        *:*) ;;
        *) fail "$label listen address must include a port, for example :2053 or 127.0.0.1:2053" ;;
    esac
    port="${value##*:}"
    case "$port" in
        ""|*[!0-9]*) fail "$label listen address has an invalid port: $value" ;;
    esac
    if [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
        fail "$label listen port must be between 1 and 65535"
    fi
    host="${value%:*}"
    case "$host" in
        ""|"localhost") return 0 ;;
        \[*\])
            host="${host#\[}"
            host="${host%\]}"
            case "$host" in
                *[!0-9A-Fa-f:.]*) fail "$label listen address must bind to a local IP, localhost, or all interfaces; public DNS names belong in client URLs" ;;
            esac
            return 0
            ;;
        *:*) fail "$label IPv6 bind address must be wrapped in brackets, for example [::]:$port" ;;
        *[!0-9.]*) fail "$label listen address must bind to a local IP, localhost, or all interfaces; public DNS names belong in client URLs" ;;
    esac
    is_ipv4_literal "$host" || fail "$label listen address must use a valid IPv4 address, localhost, bracketed IPv6, or all interfaces"
}

validate_virtual_ipv4_cidr() {
    local value="$1"
    local ip
    local bits
    local a
    local b
    local c
    local d
    local extra
    case "$value" in
        */*) ;;
        *) fail "default virtual IPv4 CIDR must include a prefix, for example 10.253.0.0/16" ;;
    esac
    ip="${value%/*}"
    bits="${value##*/}"
    case "$bits" in
        ""|*[!0-9]*) fail "default virtual IPv4 CIDR prefix is invalid: $value" ;;
    esac
    [ "$bits" -ge 16 ] && [ "$bits" -le 24 ] || fail "default virtual IPv4 CIDR prefix must be between /16 and /24"
    IFS=. read -r a b c d extra <<< "$ip"
    [ -z "${extra:-}" ] || fail "default virtual IPv4 CIDR has an invalid IPv4 address: $value"
    for octet in "$a" "$b" "$c" "$d"; do
        case "$octet" in
            ""|*[!0-9]*) fail "default virtual IPv4 CIDR has an invalid IPv4 address: $value" ;;
        esac
        [ "$octet" -ge 0 ] && [ "$octet" -le 255 ] || fail "default virtual IPv4 CIDR has an invalid IPv4 address: $value"
    done
    if [ "$a" -eq 10 ]; then
        return 0
    fi
    if [ "$a" -eq 172 ] && [ "$b" -ge 16 ] && [ "$b" -le 31 ]; then
        return 0
    fi
    fail "default virtual IPv4 CIDR must be inside 10.0.0.0/8 or 172.16.0.0/12; do not use CGNAT 100.64.0.0/10, home LAN 192.168.0.0/16, or public ranges"
}

write_full_env_file() {
    local tmp_env
    tmp_env="$(mktemp)"
    cat > "$tmp_env" <<ENV
VELORAMESH_API_BIND_ADDR=$API_BIND_ADDR
VELORAMESH_EDGE_BIND_ADDR=$EDGE_BIND_ADDR
VELORAMESH_SERVER_TLS_CERT=$TLS_CERT
VELORAMESH_SERVER_TLS_KEY=$TLS_KEY
VELORAMESH_STORE_BACKEND=sqlite
VELORAMESH_STORE_PATH=$DATA_DIR/veloramesh.db
VELORAMESH_DEFAULT_VIRTUAL_IPV4_CIDR=$DEFAULT_VIRTUAL_IPV4_CIDR
VELORAMESH_TICKET_KEY_FILE=$DATA_DIR/membership-ticket.key
VELORAMESH_EDGE_TICKET_KEY_FILE=$DATA_DIR/edge-ticket.key
VELORAMESH_MEMBERSHIP_TICKET_TTL=60s
VELORAMESH_SHUTDOWN_TIMEOUT=10s
VELORAMESH_READ_HEADER_TIMEOUT=5s
VELORAMESH_READ_TIMEOUT=15s
VELORAMESH_WRITE_TIMEOUT=15s
VELORAMESH_IDLE_TIMEOUT=60s
VELORAMESH_RATE_LIMIT_WINDOW=1m
VELORAMESH_RATE_LIMIT_MAX=120
VELORAMESH_AUTH_RATE_LIMIT_WINDOW=1m
VELORAMESH_AUTH_RATE_LIMIT_MAX=20
VELORAMESH_EDGE_RATE_LIMIT_WINDOW=1m
VELORAMESH_EDGE_RATE_LIMIT_MAX=1200
VELORAMESH_TRUST_PROXY_HEADERS=0
VELORAMESH_TRUSTED_PROXY_CIDRS=
ENV
    install -o root -g "$SERVICE_GROUP" -m 0640 "$tmp_env" "$ENV_FILE"
    rm -f "$tmp_env"
}

write_edge_env_file() {
    local tmp_env
    tmp_env="$(mktemp)"
    cat > "$tmp_env" <<ENV
VELORAMESH_EDGE_BIND_ADDR=$EDGE_BIND_ADDR
VELORAMESH_EDGE_TICKET_KEY_FILE=$DATA_DIR/edge-ticket.key
VELORAMESH_SHUTDOWN_TIMEOUT=10s
VELORAMESH_EDGE_RATE_LIMIT_WINDOW=1m
VELORAMESH_EDGE_RATE_LIMIT_MAX=1200
ENV
    install -o root -g "$SERVICE_GROUP" -m 0640 "$tmp_env" "$ENV_FILE"
    rm -f "$tmp_env"
}

while [ "$#" -gt 0 ]; do
    case "$1" in
        --role)
            [ "$#" -ge 2 ] || fail "--role requires all, api, or edge"
            ROLE="$(normalize_role "$2")"
            shift 2
            ;;
        --api-bind)
            [ "$#" -ge 2 ] || fail "--api-bind requires a listen address"
            API_BIND_ADDR="$2"
            API_BIND_ADDR_EXPLICIT=1
            shift 2
            ;;
        --edge-bind)
            [ "$#" -ge 2 ] || fail "--edge-bind requires a listen address"
            EDGE_BIND_ADDR="$2"
            EDGE_BIND_ADDR_EXPLICIT=1
            shift 2
            ;;
        --default-virtual-ipv4-cidr)
            [ "$#" -ge 2 ] || fail "--default-virtual-ipv4-cidr requires a CIDR"
            DEFAULT_VIRTUAL_IPV4_CIDR="$2"
            DEFAULT_VIRTUAL_IPV4_CIDR_EXPLICIT=1
            shift 2
            ;;
        --binary)
            [ "$#" -ge 2 ] || fail "--binary requires a path"
            SOURCE_BINARY="$2"
            shift 2
            ;;
        --edge-binary)
            [ "$#" -ge 2 ] || fail "--edge-binary requires a path"
            EDGE_SOURCE_BINARY="$2"
            shift 2
            ;;
        --edge-ticket-key)
            [ "$#" -ge 2 ] || fail "--edge-ticket-key requires a path"
            EDGE_TICKET_KEY_SOURCE="$2"
            shift 2
            ;;
        --no-start)
            START_SERVICE=0
            shift
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *)
            fail "unknown option: $1"
            ;;
    esac
done

ROLE="$(normalize_role "$ROLE")"
INSTALL_API=0
INSTALL_EDGE=0
CREATE_EDGE_KEY=0
case "$ROLE" in
    all)
        INSTALL_API=1
        INSTALL_EDGE=1
        CREATE_EDGE_KEY=1
        ;;
    api)
        INSTALL_API=1
        CREATE_EDGE_KEY=1
        ;;
    edge)
        INSTALL_EDGE=1
        ;;
esac

[ "$(id -u)" -eq 0 ] || fail "run this installer as root"

resolve_existing_listen_addrs
if [ "$INSTALL_API" -eq 1 ]; then
    validate_listen_addr "API" "$API_BIND_ADDR"
    validate_virtual_ipv4_cidr "$DEFAULT_VIRTUAL_IPV4_CIDR"
fi
if [ "$INSTALL_EDGE" -eq 1 ] || [ "$CREATE_EDGE_KEY" -eq 1 ]; then
    validate_listen_addr "Edge" "$EDGE_BIND_ADDR"
fi

need_command install
need_command getent
need_command id
need_command systemctl
need_command useradd
need_command groupadd
need_command mktemp
need_command find
need_command grep
need_command sed

if [ "$INSTALL_API" -eq 1 ]; then
    [ -f "$SOURCE_BINARY" ] || fail "server binary not found: $SOURCE_BINARY"
fi
if [ "$INSTALL_EDGE" -eq 1 ] || [ "$CREATE_EDGE_KEY" -eq 1 ]; then
    [ -f "$EDGE_SOURCE_BINARY" ] || fail "edge binary not found: $EDGE_SOURCE_BINARY"
fi
if [ -n "$EDGE_TICKET_KEY_SOURCE" ]; then
    [ -f "$EDGE_TICKET_KEY_SOURCE" ] || fail "edge ticket key not found: $EDGE_TICKET_KEY_SOURCE"
fi

if ! getent group "$SERVICE_GROUP" >/dev/null; then
    log "creating group $SERVICE_GROUP"
    groupadd --system "$SERVICE_GROUP"
fi

if ! id -u "$SERVICE_USER" >/dev/null 2>&1; then
    log "creating service user $SERVICE_USER"
    useradd --system --gid "$SERVICE_GROUP" --home-dir "$DATA_DIR" --shell /usr/sbin/nologin "$SERVICE_USER"
fi

log "install role: $(role_label)"
log "creating directories"
install -d -o root -g root -m 0755 "$INSTALL_DIR"
install -d -o root -g "$SERVICE_GROUP" -m 0750 "$CONFIG_DIR"
if [ "$INSTALL_API" -eq 1 ]; then
    install -d -o root -g "$SERVICE_GROUP" -m 0750 "$TLS_DIR"
fi
install -d -o "$SERVICE_USER" -g "$SERVICE_GROUP" -m 0750 "$DATA_DIR"
repair_data_permissions
REMOVE_EDGE_BINARY_AFTER_KEY=0

if [ "$INSTALL_API" -eq 1 ]; then
    log "installing API binary"
    install -o root -g root -m 0755 "$SOURCE_BINARY" "$INSTALL_DIR/veloramesh-server"
else
    systemctl stop "$SERVICE_NAME" 2>/dev/null || true
    systemctl disable "$SERVICE_NAME" 2>/dev/null || true
    rm -f -- "$UNIT_FILE" "$INSTALL_DIR/veloramesh-server"
fi

if [ "$INSTALL_EDGE" -eq 1 ]; then
    log "installing edge binary"
    install -o root -g root -m 0755 "$EDGE_SOURCE_BINARY" "$INSTALL_DIR/veloramesh-edge"
else
    systemctl stop "$EDGE_SERVICE_NAME" 2>/dev/null || true
    systemctl disable "$EDGE_SERVICE_NAME" 2>/dev/null || true
    rm -f -- "$EDGE_UNIT_FILE"
    REMOVE_EDGE_BINARY_AFTER_KEY=1
fi

if [ ! -f "$ENV_FILE" ]; then
    log "creating environment file"
    if [ "$ROLE" = "edge" ]; then
        write_edge_env_file
    else
        write_full_env_file
    fi
else
    log "keeping existing environment file"
fi

if [ "$ROLE" = "edge" ]; then
    remove_env_values \
        VELORAMESH_API_BIND_ADDR \
        VELORAMESH_SERVER_TLS_CERT \
        VELORAMESH_SERVER_TLS_KEY \
        VELORAMESH_STORE_BACKEND \
        VELORAMESH_STORE_PATH \
        VELORAMESH_TICKET_KEY_FILE \
        VELORAMESH_SERVER_ALLOW_INSECURE \
        VELORAMESH_MAX_BODY_BYTES \
        VELORAMESH_SESSION_TTL \
        VELORAMESH_MEMBERSHIP_TICKET_TTL \
        VELORAMESH_READ_HEADER_TIMEOUT \
        VELORAMESH_READ_TIMEOUT \
        VELORAMESH_WRITE_TIMEOUT \
        VELORAMESH_IDLE_TIMEOUT \
        VELORAMESH_RATE_LIMIT_WINDOW \
        VELORAMESH_RATE_LIMIT_MAX \
        VELORAMESH_AUTH_RATE_LIMIT_WINDOW \
        VELORAMESH_AUTH_RATE_LIMIT_MAX \
        VELORAMESH_DEFAULT_VIRTUAL_IPV4_CIDR \
        VELORAMESH_TRUST_PROXY_HEADERS \
        VELORAMESH_TRUSTED_PROXY_CIDRS
else
    set_env_value VELORAMESH_API_BIND_ADDR "$API_BIND_ADDR"
    set_env_value VELORAMESH_SERVER_TLS_CERT "$TLS_CERT"
    set_env_value VELORAMESH_SERVER_TLS_KEY "$TLS_KEY"
    set_env_value VELORAMESH_STORE_BACKEND "sqlite"
    set_env_value VELORAMESH_STORE_PATH "$DATA_DIR/veloramesh.db"
    set_env_value VELORAMESH_DEFAULT_VIRTUAL_IPV4_CIDR "$DEFAULT_VIRTUAL_IPV4_CIDR"
    set_env_value VELORAMESH_TICKET_KEY_FILE "$DATA_DIR/membership-ticket.key"
    set_env_value VELORAMESH_MEMBERSHIP_TICKET_TTL "60s"
    set_env_value VELORAMESH_READ_HEADER_TIMEOUT "5s"
    set_env_value VELORAMESH_READ_TIMEOUT "15s"
    set_env_value VELORAMESH_WRITE_TIMEOUT "15s"
    set_env_value VELORAMESH_IDLE_TIMEOUT "60s"
    set_env_value VELORAMESH_RATE_LIMIT_WINDOW "1m"
    set_env_value VELORAMESH_RATE_LIMIT_MAX "120"
    set_env_value VELORAMESH_AUTH_RATE_LIMIT_WINDOW "1m"
    set_env_value VELORAMESH_AUTH_RATE_LIMIT_MAX "20"
    set_env_value VELORAMESH_TRUST_PROXY_HEADERS "0"
    set_env_value VELORAMESH_TRUSTED_PROXY_CIDRS ""
fi
set_env_value VELORAMESH_EDGE_BIND_ADDR "$EDGE_BIND_ADDR"
set_env_value VELORAMESH_EDGE_TICKET_KEY_FILE "$DATA_DIR/edge-ticket.key"
set_env_value VELORAMESH_SHUTDOWN_TIMEOUT "10s"
set_env_value VELORAMESH_EDGE_RATE_LIMIT_WINDOW "1m"
set_env_value VELORAMESH_EDGE_RATE_LIMIT_MAX "1200"
chown root:"$SERVICE_GROUP" "$ENV_FILE"
chmod 0640 "$ENV_FILE"

if [ -n "$EDGE_TICKET_KEY_SOURCE" ]; then
    log "installing edge ticket key"
    install -o "$SERVICE_USER" -g "$SERVICE_GROUP" -m 0640 "$EDGE_TICKET_KEY_SOURCE" "$DATA_DIR/edge-ticket.key"
elif [ "$CREATE_EDGE_KEY" -eq 1 ] && [ ! -f "$DATA_DIR/edge-ticket.key" ]; then
    log "creating edge ticket key"
    run_edge_init_key
elif [ "$INSTALL_EDGE" -eq 1 ] && [ ! -f "$DATA_DIR/edge-ticket.key" ]; then
    log "edge ticket key is missing"
    log "copy the API host key to $DATA_DIR/edge-ticket.key or rerun with --edge-ticket-key <path>"
fi
if [ -f "$DATA_DIR/edge-ticket.key" ]; then
    chown "$SERVICE_USER:$SERVICE_GROUP" "$DATA_DIR/edge-ticket.key"
    chmod 0640 "$DATA_DIR/edge-ticket.key"
fi
if [ "$REMOVE_EDGE_BINARY_AFTER_KEY" -eq 1 ]; then
    rm -f -- "$INSTALL_DIR/veloramesh-edge"
fi

if [ "$INSTALL_API" -eq 1 ] && [ -f "$TLS_CERT" ]; then
    chown root:"$SERVICE_GROUP" "$TLS_CERT"
    chmod 0644 "$TLS_CERT"
fi

if [ "$INSTALL_API" -eq 1 ] && [ -f "$TLS_KEY" ]; then
    chown root:"$SERVICE_GROUP" "$TLS_KEY"
    chmod 0640 "$TLS_KEY"
fi

if [ "$INSTALL_API" -eq 1 ]; then
    log "installing API systemd unit"
    tmp_unit="$(mktemp)"
    cat > "$tmp_unit" <<UNIT
[Unit]
Description=VeloraMesh control plane
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=$SERVICE_USER
Group=$SERVICE_GROUP
EnvironmentFile=$ENV_FILE
ExecStart=$INSTALL_DIR/veloramesh-server
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=$DATA_DIR

[Install]
WantedBy=multi-user.target
UNIT
    install -o root -g root -m 0644 "$tmp_unit" "$UNIT_FILE"
    rm -f "$tmp_unit"
fi

if [ "$INSTALL_EDGE" -eq 1 ]; then
    log "installing edge systemd unit"
    tmp_edge_unit="$(mktemp)"
    cat > "$tmp_edge_unit" <<UNIT
[Unit]
Description=VeloraMesh UDP discovery edge
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=$SERVICE_USER
Group=$SERVICE_GROUP
EnvironmentFile=$ENV_FILE
ExecStart=$INSTALL_DIR/veloramesh-edge
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadOnlyPaths=$DATA_DIR

[Install]
WantedBy=multi-user.target
UNIT
    install -o root -g root -m 0644 "$tmp_edge_unit" "$EDGE_UNIT_FILE"
    rm -f "$tmp_edge_unit"
fi

systemctl daemon-reload

if [ "$START_SERVICE" -eq 0 ]; then
    log "installed $(role_label) without starting services"
    case "$ROLE" in
        all) log "after TLS is installed, run: sudo systemctl enable --now $SERVICE_NAME $EDGE_SERVICE_NAME" ;;
        api) log "after TLS is installed, run: sudo systemctl enable --now $SERVICE_NAME" ;;
        edge) log "after the edge ticket key is installed, run: sudo systemctl enable --now $EDGE_SERVICE_NAME" ;;
    esac
    exit 0
fi

if [ "$INSTALL_API" -eq 1 ] && { [ ! -f "$TLS_CERT" ] || [ ! -f "$TLS_KEY" ]; }; then
    log "TLS files are missing; service was installed but not started"
    log "expected cert: $TLS_CERT"
    log "expected key: $TLS_KEY"
    if [ "$ROLE" = "all" ]; then
        log "after TLS is installed, run: sudo systemctl enable --now $SERVICE_NAME $EDGE_SERVICE_NAME"
    else
        log "after TLS is installed, run: sudo systemctl enable --now $SERVICE_NAME"
    fi
    exit 0
fi

if [ "$INSTALL_EDGE" -eq 1 ] && [ ! -f "$DATA_DIR/edge-ticket.key" ]; then
    log "edge ticket key is missing; edge service was installed but not started"
    log "copy the API host key to $DATA_DIR/edge-ticket.key or rerun with --edge-ticket-key <path>"
    exit 0
fi

case "$ROLE" in
    all)
        log "enabling and starting API and edge services"
        systemctl enable --now "$SERVICE_NAME" "$EDGE_SERVICE_NAME"
        systemctl --no-pager --full status "$SERVICE_NAME"
        systemctl --no-pager --full status "$EDGE_SERVICE_NAME"
        ;;
    api)
        log "enabling and starting API service"
        systemctl enable --now "$SERVICE_NAME"
        systemctl --no-pager --full status "$SERVICE_NAME"
        ;;
    edge)
        log "enabling and starting edge service"
        systemctl enable --now "$EDGE_SERVICE_NAME"
        systemctl --no-pager --full status "$EDGE_SERVICE_NAME"
        ;;
esac
