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

INSTALL_DIR="/opt/veloramesh"
CONFIG_PATH="/etc/veloramesh/client.json"
SERVICE_NAME="${VELORAMESH_CLIENT_SERVICE_NAME:-veloramesh-client}"
SYSTEMD_DIR="${VELORAMESH_SYSTEMD_DIR:-/etc/systemd/system}"
UNIT_FILE="${SYSTEMD_DIR}/${SERVICE_NAME}.service"
SERVER_URL="https://api.veloramesh.com:2053"
DEVICE_NAME="$(hostname)"
NETWORK_NAME=""
JOIN_SECRET=""
JOIN_SECRET_FILE=""
LISTEN_ADDR="0.0.0.0:42003"
ADVERTISE_ADDR=""
DISCOVERY_SERVERS="edge.veloramesh.com:3478"
FORWARD_BROADCAST_UDP=""
INSTALL_SERVICE=0
START_SERVICE=0
SKIP_CONFIG=0
SOURCE_CLIENT=""
REPLACE_SERVICE=0
STATUS=0
FRESH=0
UNINSTALL=0
PURGE=0
NON_INTERACTIVE=0
EXPLICIT_ACTION=0
MENU_ACTION=""
SECRET_DIR=""
SERVICE_WAS_ACTIVE=0
SERVICE_WAS_ENABLED=0
STAGED_CLIENT=""
PREVIOUS_CLIENT=""
UNIT_STAGING=""
UNIT_PREVIOUS=""
UNIT_HAD_PREVIOUS=0
UNIT_REPLACED=0
CLIENT_UPDATE_PENDING=0
CLIENT_REPLACED=0
PACKAGE_UPDATED_FILES=""

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

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

usage() {
    cat <<'USAGE'
Usage: sudo bash ./install-linux-client.sh [options]

Source, path, and endpoint overrides keep the interactive action menu available.
Operation or enrollment options select the direct flow; --non-interactive never prompts for setup.

Options:
  --install-dir PATH       absolute install directory (default /opt/veloramesh)
  --config PATH            absolute client config path (default /etc/veloramesh/client.json)
  --server URL             API URL override (default https://api.veloramesh.com:2053)
  --device-name NAME       device name used when joining a new config
  --network-name NAME      network to join and/or run in the systemd service
  --join-secret-file PATH  read network join secret from a local root-readable file
  --listen IP:PORT         UDP listen address for service tunnel (default 0.0.0.0:42003)
  --advertise IP:PORT      explicit reported UDP endpoint
  --discovery HOST:PORT,... encrypted edge discovery endpoints (default: edge.veloramesh.com:3478)
  --forward-broadcast-udp PORTS
                          extra UDP broadcast ports/ranges to forward, e.g. 27015,2300-2400
  --source-client PATH     source veloramesh-client binary
  --skip-config            do not create or join config
  --background             install and start the systemd tunnel service
  --service                install systemd service
  --start                  start systemd service after install
  --replace-service        stop and replace the existing systemd service definition
  --fresh                  remove service, installed files, and config before guided install
  --uninstall              stop and remove the systemd service
  --purge                  with --uninstall, also remove installed files and config
  --status                 print systemd service status after install/start
  --non-interactive        never prompt for missing install values
  -h, --help               show help
USAGE
}

need_value() {
    if [[ $# -lt 2 || -z "${2:-}" || "${2:-}" == --* ]]; then
        fail "$1 requires a value"
    fi
}


is_interactive() {
    [[ "${NON_INTERACTIVE}" -ne 1 && -t 0 && -t 1 ]]
}

prompt_value() {
    local label="$1"
    local default="${2:-}"
    local value
    if [[ -n "${default}" ]]; then
        printf '%s [%s]: ' "${label}" "${default}" >&2
    else
        printf '%s: ' "${label}" >&2
    fi
    IFS= read -r value
    if [[ -z "${value}" ]]; then
        value="${default}"
    fi
    printf '%s' "${value}"
}

prompt_required() {
    local label="$1"
    local default="${2:-}"
    local value
    while true; do
        value="$(prompt_value "${label}" "${default}")"
        if [[ -n "${value}" ]]; then
            printf '%s' "${value}"
            return
        fi
        log "${label} is required"
    done
}

count_char() {
    local value="$1"
    local needle="$2"
    local without="${value//${needle}/}"
    printf '%s' "$(( ${#value} - ${#without} ))"
}

validate_endpoint_host() {
    local value="$1"
    [[ -n "${value}" ]] || return 1
    case "${value}" in
        *[[:space:]]*|*://*|*/*|*\?*|*\#*|*,*) return 1 ;;
    esac
    if [[ "${value}" == \[* || "${value}" == *\] ]]; then
        [[ "${value}" == \[*\] ]] || return 1
        local inner="${value:1:${#value}-2}"
        [[ "${inner}" == *:* ]] || return 1
    fi
    if [[ "${value}" != \[*\] && "$(count_char "${value}" ":")" -eq 1 ]]; then
        return 1
    fi
    return 0
}

validate_endpoint_port() {
    local value="$1"
    case "${value}" in
        ""|*[!0-9]*) return 1 ;;
    esac
    [[ "${value}" -ge 1 && "${value}" -le 65535 ]]
}

format_endpoint_host() {
    local host="$1"
    case "${host}" in
        \[*\]) printf '%s' "${host}" ;;
        *:*) printf '[%s]' "${host}" ;;
        *) printf '%s' "${host}" ;;
    esac
}

server_host_from_url() {
    local value="${1#*://}"
    value="${value%%/*}"
    value="${value%%\?*}"
    value="${value%%\#*}"
    value="${value##*@}"
    if [[ "${value}" == \[*\]* ]]; then
        value="${value#\[}"
        printf '%s' "${value%%\]*}"
        return
    fi
    if [[ "$(count_char "${value}" ":")" -eq 1 ]]; then
        printf '%s' "${value%:*}"
        return
    fi
    printf '%s' "${value}"
}

server_port_from_url() {
    local value="${1#*://}"
    value="${value%%/*}"
    value="${value%%\?*}"
    value="${value%%\#*}"
    value="${value##*@}"
    if [[ "${value}" == \[*\]*:* ]]; then
        printf '%s' "${value##*:}"
        return
    fi
    if [[ "$(count_char "${value}" ":")" -eq 1 ]]; then
        printf '%s' "${value##*:}"
        return
    fi
    printf '443'
}

discovery_host_from_endpoint() {
    local value="${1%%,*}"
    if [[ "${value}" == \[*\]* ]]; then
        value="${value#\[}"
        printf '%s' "${value%%\]*}"
        return
    fi
    if [[ "$(count_char "${value}" ":")" -eq 1 ]]; then
        printf '%s' "${value%:*}"
        return
    fi
    printf '%s' "${value}"
}

discovery_port_from_endpoint() {
    local value="${1%%,*}"
    if [[ "${value}" == \[*\]*:* ]]; then
        printf '%s' "${value##*:}"
        return
    fi
    if [[ "$(count_char "${value}" ":")" -eq 1 ]]; then
        printf '%s' "${value##*:}"
        return
    fi
    printf '3478'
}

prompt_endpoint_host() {
    local label="$1"
    local default="$2"
    local value
    while true; do
        value="$(prompt_required "${label}" "${default}")"
        if validate_endpoint_host "${value}"; then
            printf '%s' "${value}"
            return
        fi
        log "${label} must be a host name or IP address, not a URL"
    done
}

prompt_endpoint_port() {
    local label="$1"
    local default="$2"
    local value
    while true; do
        value="$(prompt_required "${label}" "${default}")"
        if validate_endpoint_port "${value}"; then
            printf '%s' "${value}"
            return
        fi
        log "${label} must be a port between 1 and 65535"
    done
}

prompt_api_endpoint() {
    local host
    local port
    host="$(prompt_endpoint_host "API host/domain" "$(server_host_from_url "${SERVER_URL}")")"
    port="$(prompt_endpoint_port "API HTTPS port" "$(server_port_from_url "${SERVER_URL}")")"
    SERVER_URL="https://$(format_endpoint_host "${host}"):${port}"
}

prompt_discovery_endpoint() {
    local host
    local port
    host="$(prompt_endpoint_host "Edge discovery host/domain" "$(discovery_host_from_endpoint "${DISCOVERY_SERVERS}")")"
    port="$(prompt_endpoint_port "Edge UDP port" "$(discovery_port_from_endpoint "${DISCOVERY_SERVERS}")")"
    DISCOVERY_SERVERS="$(format_endpoint_host "${host}"):${port}"
}

prompt_secret() {
    local label="$1"
    local value
    while true; do
        printf '%s: ' "${label}" >&2
        IFS= read -r -s value
        printf '\n' >&2
        if [[ -n "${value}" ]]; then
            printf '%s' "${value}"
            return
        fi
        log "${label} is required"
    done
}

prompt_yes_no() {
    local label="$1"
    local default="${2:-Y}"
    local value
    local suffix="[Y/n]"
    if [[ "${default}" != "Y" ]]; then
        suffix="[y/N]"
    fi
    while true; do
        printf '%s %s: ' "${label}" "${suffix}" >&2
        IFS= read -r value
        value="$(printf '%s' "${value}" | tr '[:upper:]' '[:lower:]')"
        if [[ -z "${value}" ]]; then
            [[ "${default}" == "Y" ]]
            return
        fi
        case "${value}" in
            y|yes|e|evet) return 0 ;;
            n|no|h|hayir|hayır) return 1 ;;
        esac
    done
}

confirm_phrase() {
    local message="$1"
    local phrase="$2"
    local answer
    printf '%s Type %s to continue: ' "${message}" "${phrase}" >&2
    IFS= read -r answer
    [[ "${answer}" == "${phrase}" ]]
}

configure_interactive_action() {
    if ! is_interactive || [[ "${EXPLICIT_ACTION}" -eq 1 ]]; then
        return
    fi

    local choice
    while true; do
        cat <<MENU

VeloraMesh Linux Client Installer
1) Guided install/update
2) Network operations
3) Service operations
4) Fresh install/reset client
5) Uninstall service, keep files/config
6) Purge client install and config
0) Exit
MENU
        printf 'Select: ' >&2
        IFS= read -r choice
        case "${choice}" in
            1) return ;;
            2) MENU_ACTION="network"; return ;;
            3) MENU_ACTION="service"; return ;;
            4) FRESH=1; return ;;
            5) UNINSTALL=1; return ;;
            6) UNINSTALL=1; PURGE=1; return ;;
            0) exit 0 ;;
            *) log "unknown selection" ;;
        esac
    done
}

has_join_secret_input() {
    [[ -n "${JOIN_SECRET}" || -n "${JOIN_SECRET_FILE}" ]]
}


client_env() {
    VELORAMESH_SECRET_DIR="${SECRET_DIR}" "$@"
}

systemd_quote() {
    local value="$1"
    value="${value//\\/\\\\}"
    value="${value//\"/\\\"}"
    value="${value//%/%%}"
    value="${value//$'\n'/\\n}"
    value="${value//$'\r'/\\r}"
    value="${value//$'\t'/\\t}"
    if [[ "${2:-}" == "argument" ]]; then
        value="${value//\$/\$\$}"
    fi
    printf '"%s"' "${value}"
}

rollback_client_update() {
    local status="$?"
    trap - EXIT
    if [[ "${CLIENT_UPDATE_PENDING}" -eq 1 ]]; then
        local optional
        for optional in ${PACKAGE_UPDATED_FILES}; do
            if [[ -f "${INSTALL_DIR}/.${optional}.previous.$$" ]]; then
                mv -f "${INSTALL_DIR}/.${optional}.previous.$$" "${INSTALL_DIR}/${optional}"
            else
                rm -f -- "${INSTALL_DIR}/${optional}"
            fi
        done
        clear_package_transaction_files
        if systemctl is-active --quiet "${SERVICE_NAME}"; then
            systemctl stop "${SERVICE_NAME}" >/dev/null 2>&1 || true
        fi
        rm -f -- "${STAGED_CLIENT}" "${UNIT_STAGING}"
        if [[ "${UNIT_REPLACED}" -eq 1 ]]; then
            if [[ "${UNIT_HAD_PREVIOUS}" -eq 1 && -f "${UNIT_PREVIOUS}" ]]; then
                mv -f "${UNIT_PREVIOUS}" "${UNIT_FILE}"
            else
                rm -f "${UNIT_FILE}"
            fi
            systemctl daemon-reload >/dev/null 2>&1 || true
        fi
        rm -f -- "${UNIT_PREVIOUS}"
        if [[ -n "${PREVIOUS_CLIENT}" && -f "${PREVIOUS_CLIENT}" ]]; then
            rm -f -- "${INSTALL_DIR}/veloramesh-client"
            mv "${PREVIOUS_CLIENT}" "${INSTALL_DIR}/veloramesh-client"
        elif [[ "${CLIENT_REPLACED}" -eq 1 ]]; then
            rm -f -- "${INSTALL_DIR}/veloramesh-client"
        fi
        if [[ "${SERVICE_WAS_ENABLED}" -eq 1 ]]; then
            systemctl enable "${SERVICE_NAME}" >/dev/null 2>&1 || true
        else
            systemctl disable "${SERVICE_NAME}" >/dev/null 2>&1 || true
        fi
        if [[ "${SERVICE_WAS_ACTIVE}" -eq 1 ]]; then
            systemctl start "${SERVICE_NAME}" >/dev/null 2>&1 || true
        fi
    fi
    exit "${status}"
}

install_client_binary_atomically() {
    STAGED_CLIENT="${INSTALL_DIR}/.veloramesh-client.new.$$"
    PREVIOUS_CLIENT="${INSTALL_DIR}/.veloramesh-client.previous.$$"
    rm -f -- "${STAGED_CLIENT}" "${PREVIOUS_CLIENT}"
    if ! install -o root -g root -m 0755 "${SOURCE_CLIENT}" "${STAGED_CLIENT}"; then
        rm -f -- "${STAGED_CLIENT}"
        fail "could not stage the client binary"
    fi
    if ! client_env "${STAGED_CLIENT}" version >/dev/null; then
        rm -f -- "${STAGED_CLIENT}"
        fail "candidate client binary failed validation"
    fi

    if systemctl is-enabled --quiet "${SERVICE_NAME}"; then
        SERVICE_WAS_ENABLED=1
    fi
    if systemctl is-active --quiet "${SERVICE_NAME}"; then
        SERVICE_WAS_ACTIVE=1
    fi
    CLIENT_UPDATE_PENDING=1
    trap rollback_client_update EXIT
    if [[ "${SERVICE_WAS_ACTIVE}" -eq 1 ]]; then
        log "stopping active systemd service for binary update"
        systemctl stop "${SERVICE_NAME}"
    fi
    if [[ -e "${INSTALL_DIR}/veloramesh-client" ]]; then
        mv "${INSTALL_DIR}/veloramesh-client" "${PREVIOUS_CLIENT}"
    fi
    mv "${STAGED_CLIENT}" "${INSTALL_DIR}/veloramesh-client"
    CLIENT_REPLACED=1
}

commit_client_update() {
    clear_package_transaction_files
    rm -f -- "${STAGED_CLIENT}" "${PREVIOUS_CLIENT}" "${UNIT_STAGING}" "${UNIT_PREVIOUS}"
    CLIENT_UPDATE_PENDING=0
    trap - EXIT
}

clear_package_transaction_files() {
    local optional
    for optional in manifest.json RELEASE-NOTES.md; do
        rm -f -- "${INSTALL_DIR}/.${optional}.new.$$" "${INSTALL_DIR}/.${optional}.previous.$$"
    done
}

install_package_metadata() {
    local optional
    for optional in manifest.json RELEASE-NOTES.md; do
        if [[ -f "${SCRIPT_DIR}/${optional}" ]]; then
            install -o root -g root -m 0644 "${SCRIPT_DIR}/${optional}" "${INSTALL_DIR}/.${optional}.new.$$"
            if [[ -f "${INSTALL_DIR}/${optional}" ]]; then
                cp -p "${INSTALL_DIR}/${optional}" "${INSTALL_DIR}/.${optional}.previous.$$"
            fi
            PACKAGE_UPDATED_FILES+=" ${optional}"
            mv -f "${INSTALL_DIR}/.${optional}.new.$$" "${INSTALL_DIR}/${optional}"
        fi
    done
}

run_installer_self_test() {
    [[ -x "${INSTALL_DIR}/veloramesh-client" && -f "${CONFIG_PATH}" ]] || return 0
    log "running installer self-test"
    local args=(doctor -config "${CONFIG_PATH}" -timeout 8s)
    if [[ -n "${NETWORK_NAME}" ]]; then
        local network_id="${NETWORK_ID:-}"
        if [[ -z "${network_id}" ]]; then
            network_id="$(configured_network_id || true)"
        fi
        if [[ -n "${network_id}" ]]; then
            args+=( -id "${network_id}" )
        else
            args+=( -network "${NETWORK_NAME}" )
        fi
        if [[ -n "${DISCOVERY_SERVERS}" ]]; then
            args+=( -discovery "${DISCOVERY_SERVERS}" )
        fi
    else
        args+=( -local-only )
    fi
    if client_env "${INSTALL_DIR}/veloramesh-client" "${args[@]}"; then
        log "self-test passed"
    else
        log "self-test reported issues; run the doctor command above for details"
    fi
}

configure_interactive_install() {
    if ! is_interactive || [[ "${UNINSTALL}" -eq 1 ]]; then
        return
    fi

    log "interactive setup"
    if [[ "${SKIP_CONFIG}" -eq 0 && ! -f "${CONFIG_PATH}" && -z "${NETWORK_NAME}" ]]; then
        prompt_api_endpoint
        NETWORK_NAME="$(prompt_value "Network name (blank to create config only)" "")"
        DEVICE_NAME="$(prompt_required "Device name" "${DEVICE_NAME}")"
        if [[ -n "${NETWORK_NAME}" ]]; then
            JOIN_SECRET="$(prompt_secret "Network join secret")"
            prompt_discovery_endpoint
        fi
    fi

    if [[ "${INSTALL_SERVICE}" -eq 0 && "${START_SERVICE}" -eq 0 && "${SKIP_CONFIG}" -eq 0 && -n "${NETWORK_NAME}" ]]; then
        if prompt_yes_no "Install and start the background tunnel service?" "Y"; then
            INSTALL_SERVICE=1
            START_SERVICE=1
        fi
    fi
}

invoke_network_join_once() (
    local secret_file="${JOIN_SECRET_FILE}"
    local transient_secret_file=""

    if [[ -n "${JOIN_SECRET}" ]]; then
        [[ -z "${secret_file}" ]] || fail "use either the interactive secret or --join-secret-file"
        umask 077
        install -d -o root -g root -m 0700 "${SECRET_DIR}" || return 1
        transient_secret_file="$(mktemp "${SECRET_DIR}/.join-secret.XXXXXX")" || return 1
        trap 'rm -f -- "${transient_secret_file}"' EXIT
        chmod 0600 "${transient_secret_file}" || return 1
        printf '%s' "${JOIN_SECRET}" > "${transient_secret_file}" || return 1
        secret_file="${transient_secret_file}"
    fi
    [[ -n "${secret_file}" ]] || fail "--join-secret-file is required with --network-name in non-interactive mode"

    client_env "${INSTALL_DIR}/veloramesh-client" network join \
        -server "${SERVER_URL}" \
        -name "${NETWORK_NAME}" \
        -join-secret-file "${secret_file}" \
        -device-name "${DEVICE_NAME}" \
        -config "${CONFIG_PATH}"
)

join_network_with_retry() {
    while true; do
        log "joining network ${NETWORK_NAME}"
        if invoke_network_join_once; then
            return
        fi
        if ! is_interactive; then
            fail "veloramesh-client network join failed"
        fi
        if ! prompt_yes_no "Try another network name or join secret?" "Y"; then
            fail "veloramesh-client network join failed"
        fi
        NETWORK_NAME="$(prompt_required "Network name" "${NETWORK_NAME}")"
        JOIN_SECRET="$(prompt_secret "Network join secret")"
        JOIN_SECRET_FILE=""
    done
}

configured_network_id() {
    local output
    output="$(client_env "${INSTALL_DIR}/veloramesh-client" network status -config "${CONFIG_PATH}" 2>/dev/null || true)"
    awk -v want="${NETWORK_NAME}" '
        $1 == "network" && $2 == want {
            print $3
            found = 1
            exit
        }
        $1 == "network" && $0 ~ /auto_connect=true/ {
            auto_count++
            auto_id = $3
        }
        END {
            if (!found && auto_count == 1) {
                print auto_id
            }
        }
    ' <<< "${output}"
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        --network-name|--join-secret-file|--skip-config|--background|--service|--start|--replace-service|--fresh|--uninstall|--purge|--status)
            EXPLICIT_ACTION=1 ;;
    esac
    case "$1" in
        --install-dir) need_value "$1" "${2:-}"; INSTALL_DIR="$2"; shift 2 ;;
        --config) need_value "$1" "${2:-}"; CONFIG_PATH="$2"; shift 2 ;;
        --server) need_value "$1" "${2:-}"; SERVER_URL="$2"; shift 2 ;;
        --device-name) need_value "$1" "${2:-}"; DEVICE_NAME="$2"; shift 2 ;;
        --network-name) need_value "$1" "${2:-}"; NETWORK_NAME="$2"; shift 2 ;;
        --join-secret-file) need_value "$1" "${2:-}"; JOIN_SECRET_FILE="$2"; shift 2 ;;
        --listen) need_value "$1" "${2:-}"; LISTEN_ADDR="$2"; shift 2 ;;
        --advertise) need_value "$1" "${2:-}"; ADVERTISE_ADDR="$2"; shift 2 ;;
        --discovery) need_value "$1" "${2:-}"; DISCOVERY_SERVERS="$2"; shift 2 ;;
        --forward-broadcast-udp) need_value "$1" "${2:-}"; FORWARD_BROADCAST_UDP="$2"; shift 2 ;;
        --source-client) need_value "$1" "${2:-}"; SOURCE_CLIENT="$2"; shift 2 ;;
        --skip-config) SKIP_CONFIG=1; shift ;;
        --background) INSTALL_SERVICE=1; START_SERVICE=1; shift ;;
        --service) INSTALL_SERVICE=1; shift ;;
        --start) START_SERVICE=1; shift ;;
        --replace-service) REPLACE_SERVICE=1; shift ;;
        --fresh) FRESH=1; shift ;;
        --uninstall) UNINSTALL=1; shift ;;
        --purge) PURGE=1; shift ;;
        --status) STATUS=1; shift ;;
        --non-interactive) NON_INTERACTIVE=1; shift ;;
        -h|--help) usage; exit 0 ;;
        *) usage >&2; fail "unknown option: $1" ;;
    esac
done

if [[ "${EUID}" -ne 0 ]]; then
    fail "install-linux-client.sh must run as root"
fi
[[ "${INSTALL_DIR}" == /* ]] || fail "--install-dir must be an absolute path"
[[ "${CONFIG_PATH}" == /* ]] || fail "--config must be an absolute path"
[[ "${SYSTEMD_DIR}" == /* ]] || fail "VELORAMESH_SYSTEMD_DIR must be an absolute path"
[[ "${SERVICE_NAME}" =~ ^[A-Za-z0-9_.@-]+$ ]] || fail "invalid systemd service name: ${SERVICE_NAME}"
SECRET_DIR="$(dirname "${CONFIG_PATH}")/secrets"
configure_interactive_action
if [[ "${FRESH}" -eq 1 && "${UNINSTALL}" -eq 1 ]]; then
    fail "--fresh cannot be combined with --uninstall"
fi
if [[ "${FRESH}" -eq 1 && "${START_SERVICE}" -eq 1 && "${INSTALL_SERVICE}" -eq 0 ]]; then
    fail "--fresh --start requires --service to create the replacement service"
fi
if [[ "${PURGE}" -eq 1 && "${UNINSTALL}" -ne 1 ]]; then
    fail "--purge can only be used with --uninstall"
fi

safe_purge_dir() {
    local path="$1"
    [[ -n "${path}" && "${path}" != "/" ]] || fail "refusing to purge unsafe path: ${path}"
    [[ "$(basename "${path}")" == "veloramesh" ]] || fail "refusing to purge unexpected path: ${path}"
    rm -rf "${path}"
}

safe_purge_config() {
    local path="$1"
    [[ "$(basename "${path}")" == "client.json" ]] || fail "refusing to purge unexpected config path: ${path}"
    rm -f "${path}"
    rmdir "$(dirname "${path}")" >/dev/null 2>&1 || true
}

safe_purge_secret_dir() {
    local path="$1"
    [[ -n "${path}" && "${path}" != "/" ]] || fail "refusing to purge unsafe secret path: ${path}"
    [[ "$(basename "${path}")" == "secrets" ]] || fail "refusing to purge unexpected secret path: ${path}"
    rm -rf "${path}"
}

remove_service_if_present() {
    local managed=0
    local was_active=0
    local was_enabled=0
    systemctl is-active --quiet "${SERVICE_NAME}" && was_active=1
    systemctl is-enabled --quiet "${SERVICE_NAME}" && was_enabled=1
    if [[ -f "${UNIT_FILE}" ]] || systemctl is-active --quiet "${SERVICE_NAME}" || systemctl is-enabled --quiet "${SERVICE_NAME}"; then
        managed=1
    fi
    if [[ "${managed}" -eq 1 ]]; then
        systemctl stop "${SERVICE_NAME}" || fail "could not stop ${SERVICE_NAME}; installed files were kept"
        if systemctl is-active --quiet "${SERVICE_NAME}"; then
            fail "${SERVICE_NAME} is still active; installed files were kept"
        fi
        if ! systemctl disable "${SERVICE_NAME}"; then
            [[ "${was_enabled}" -eq 0 ]] || systemctl enable "${SERVICE_NAME}" >/dev/null 2>&1 || true
            [[ "${was_active}" -eq 0 ]] || systemctl start "${SERVICE_NAME}" >/dev/null 2>&1 || true
            fail "could not disable ${SERVICE_NAME}; installed files were kept"
        fi
        if systemctl is-enabled --quiet "${SERVICE_NAME}"; then
            [[ "${was_active}" -eq 0 ]] || systemctl start "${SERVICE_NAME}" >/dev/null 2>&1 || true
            fail "${SERVICE_NAME} is still enabled; installed files were kept"
        fi
    fi
    rm -f "${UNIT_FILE}"
    systemctl daemon-reload
}

remove_installed_files_and_config() {
    safe_purge_dir "${INSTALL_DIR}"
    safe_purge_secret_dir "${SECRET_DIR}"
    safe_purge_config "${CONFIG_PATH}"
    log "removed installed files and config"
}

require_installed_client() {
    [[ -x "${INSTALL_DIR}/veloramesh-client" ]] || fail "veloramesh-client was not found at ${INSTALL_DIR}/veloramesh-client; run Guided install/update first"
}

client_cmd() {
    require_installed_client
    client_env "${INSTALL_DIR}/veloramesh-client" "$@"
}

network_operations_menu() {
    require_installed_client
    local choice
    local name
    while true; do
        cat <<MENU

VeloraMesh Linux Client - Network
1) Status
2) Join network
3) List peers
4) Disconnect network
5) Connect network
6) Leave network
7) Rename device
8) Doctor
0) Back
MENU
        printf 'Select: ' >&2
        IFS= read -r choice
        case "${choice}" in
            1) client_cmd network status -config "${CONFIG_PATH}" ;;
            2)
                prompt_api_endpoint
                NETWORK_NAME="$(prompt_required "Network name" "${NETWORK_NAME}")"
                DEVICE_NAME="$(prompt_required "Device name" "${DEVICE_NAME}")"
                JOIN_SECRET="$(prompt_secret "Network join secret")"
                JOIN_SECRET_FILE=""
                join_network_with_retry
                ;;
            3)
                name="$(prompt_required "Network name" "${NETWORK_NAME}")"
                client_cmd network peers -name "${name}" -config "${CONFIG_PATH}"
                ;;
            4)
                name="$(prompt_required "Network name" "${NETWORK_NAME}")"
                client_cmd network disconnect -name "${name}" -config "${CONFIG_PATH}"
                ;;
            5)
                name="$(prompt_required "Network name" "${NETWORK_NAME}")"
                client_cmd network connect -name "${name}" -config "${CONFIG_PATH}"
                ;;
            6)
                name="$(prompt_required "Network name" "${NETWORK_NAME}")"
                if prompt_yes_no "Leave network '${name}'?" "N"; then
                    client_cmd network leave -name "${name}" -config "${CONFIG_PATH}"
                fi
                ;;
            7)
                name="$(prompt_required "New device name" "${DEVICE_NAME}")"
                client_cmd device rename -name "${name}" -config "${CONFIG_PATH}"
                ;;
            8)
                name="$(prompt_value "Network name (blank for local checks)" "")"
                if [[ -n "${name}" ]]; then
                    client_cmd doctor -config "${CONFIG_PATH}" -network "${name}" -discovery "${DISCOVERY_SERVERS}"
                else
                    client_cmd doctor -config "${CONFIG_PATH}"
                fi
                ;;
            0) return ;;
            *) log "unknown selection" ;;
        esac
    done
}

service_operations_menu() {
    require_installed_client
    local choice
    while true; do
        cat <<MENU

VeloraMesh Linux Client - Service
1) Status
2) Start
3) Stop
4) Restart
5) Doctor
0) Back
MENU
        printf 'Select: ' >&2
        IFS= read -r choice
        case "${choice}" in
            1) systemctl --no-pager --full status "${SERVICE_NAME}" || true ;;
            2) systemctl enable --now "${SERVICE_NAME}" ;;
            3) systemctl stop "${SERVICE_NAME}" ;;
            4) systemctl restart "${SERVICE_NAME}" ;;
            5) client_cmd doctor -config "${CONFIG_PATH}" -local-only ;;
            0) return ;;
            *) log "unknown selection" ;;
        esac
    done
}

while [[ -n "${MENU_ACTION}" ]]; do
    case "${MENU_ACTION}" in
        network)
            MENU_ACTION=""
            network_operations_menu
            configure_interactive_action
            ;;
        service)
            MENU_ACTION=""
            service_operations_menu
            configure_interactive_action
            ;;
        *) break ;;
    esac
done

if [[ "${FRESH}" -eq 1 ]]; then
    if ! confirm_phrase "This removes the Linux service, installed files, and config." "FRESH"; then
        fail "fresh install cancelled"
    fi
    log "resetting existing Linux client installation"
    remove_service_if_present
    remove_installed_files_and_config
fi

if [[ "${UNINSTALL}" -eq 1 ]]; then
    log "stopping and removing systemd service if present"
    remove_service_if_present
    if [[ "${PURGE}" -eq 1 ]]; then
        remove_installed_files_and_config
    else
        log "kept installed files and config; rerun with --purge to remove them"
    fi
    log "uninstall complete"
    exit 0
fi

configure_interactive_install

if [[ "${START_SERVICE}" -eq 1 && "${INSTALL_SERVICE}" -eq 0 && ! -f "${UNIT_FILE}" ]]; then
    fail "--start requires an installed service; use --service --start for first installation"
fi

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [[ -z "${SOURCE_CLIENT}" ]]; then
    if [[ -x "${SCRIPT_DIR}/veloramesh-client" ]]; then
        SOURCE_CLIENT="${SCRIPT_DIR}/veloramesh-client"
    else
        fail "veloramesh-client was not found; run from the Linux client package or pass --source-client"
    fi
fi

install -d -m 0755 "${INSTALL_DIR}"
install -d -m 0700 "$(dirname "${CONFIG_PATH}")"
install -d -m 0700 "${SECRET_DIR}"
chown root:root "$(dirname "${CONFIG_PATH}")" "${SECRET_DIR}"
chmod 0700 "$(dirname "${CONFIG_PATH}")" "${SECRET_DIR}"

log "installing client binary"
install_client_binary_atomically

install_package_metadata

log "installed version"
client_env "${INSTALL_DIR}/veloramesh-client" version

if [[ "${SKIP_CONFIG}" -eq 1 ]]; then
    log "skipping config initialization"
elif [[ -f "${CONFIG_PATH}" ]]; then
    log "keeping existing config ${CONFIG_PATH}"
    if [[ -n "${NETWORK_NAME}" ]] && has_join_secret_input; then
        join_network_with_retry
    fi
elif [[ -n "${NETWORK_NAME}" ]]; then
    join_network_with_retry
else
    log "creating config ${CONFIG_PATH}"
    client_env "${INSTALL_DIR}/veloramesh-client" config init \
        -server "${SERVER_URL}" \
        -name "${DEVICE_NAME}" \
        -config "${CONFIG_PATH}"
fi

if [[ -f "${CONFIG_PATH}" ]]; then
    chmod 0600 "${CONFIG_PATH}"
fi

if [[ "${INSTALL_SERVICE}" -eq 1 ]]; then
    if [[ -z "${NETWORK_NAME}" ]]; then
        fail "--network-name is required with --service"
    fi
    NETWORK_ID="$(configured_network_id)"
    if [[ "${REPLACE_SERVICE}" -eq 1 ]]; then
        log "replacing the systemd service transactionally"
    fi

    SERVICE_ARGS=(
        "${INSTALL_DIR}/veloramesh-client" run-network
        -config "${CONFIG_PATH}"
        -listen "${LISTEN_ADDR}"
    )
    if [[ -n "${NETWORK_ID}" ]]; then
        SERVICE_ARGS+=( -id "${NETWORK_ID}" )
        log "service network_id=${NETWORK_ID}"
    else
        SERVICE_ARGS+=( -name "${NETWORK_NAME}" )
    fi
    if [[ -n "${ADVERTISE_ADDR}" ]]; then
        SERVICE_ARGS+=( -advertise "${ADVERTISE_ADDR}" )
    fi
    if [[ -n "${DISCOVERY_SERVERS}" ]]; then
        SERVICE_ARGS+=( -discovery "${DISCOVERY_SERVERS}" )
    fi
    if [[ -n "${FORWARD_BROADCAST_UDP}" ]]; then
        SERVICE_ARGS+=( -forward-broadcast-udp "${FORWARD_BROADCAST_UDP}" )
    fi

    EXEC_START="$(systemd_quote "${SERVICE_ARGS[0]}") "
    for arg in "${SERVICE_ARGS[@]:1}"; do
        EXEC_START+="$(systemd_quote "${arg}" argument) "
    done
    EXEC_START="${EXEC_START% }"

    log "installing systemd service"
    install -d -o root -g root -m 0755 "${SYSTEMD_DIR}"
    UNIT_STAGING="${SYSTEMD_DIR}/.${SERVICE_NAME}.service.new.$$"
    UNIT_PREVIOUS="${SYSTEMD_DIR}/.${SERVICE_NAME}.service.previous.$$"
    cat > "${UNIT_STAGING}" <<SERVICE
[Unit]
Description=VeloraMesh client tunnel
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
Environment=$(systemd_quote "VELORAMESH_SECRET_DIR=${SECRET_DIR}")
ExecStart=${EXEC_START}
Restart=on-failure
RestartSec=1
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target
SERVICE

    chown root:root "${UNIT_STAGING}"
    chmod 0644 "${UNIT_STAGING}"
    if [[ -f "${UNIT_FILE}" ]]; then
        cp -p "${UNIT_FILE}" "${UNIT_PREVIOUS}"
        UNIT_HAD_PREVIOUS=1
    fi

    mv "${UNIT_STAGING}" "${UNIT_FILE}"
    UNIT_REPLACED=1
    if command -v systemd-analyze >/dev/null 2>&1; then
        systemd-analyze verify "${UNIT_FILE}"
    fi
    systemctl daemon-reload
    if [[ "${START_SERVICE}" -eq 1 ]]; then
        log "starting systemd service"
        systemctl enable --now "${SERVICE_NAME}"
    elif [[ "${SERVICE_WAS_ACTIVE}" -eq 1 ]]; then
        log "restoring active systemd service"
        if [[ "${SERVICE_WAS_ENABLED}" -eq 1 ]]; then
            systemctl enable --now "${SERVICE_NAME}"
        else
            systemctl start "${SERVICE_NAME}"
        fi
    else
        log "installed without starting service"
        log "next: sudo systemctl enable --now ${SERVICE_NAME}"
    fi
    if [[ "${START_SERVICE}" -eq 1 || "${STATUS}" -eq 1 ]]; then
        if systemctl is-active --quiet "${SERVICE_NAME}"; then
            log "service=active"
        else
            log "service=inactive"
        fi
    fi
fi

if [[ "${INSTALL_SERVICE}" -eq 0 ]]; then
    if [[ "${START_SERVICE}" -eq 1 ]]; then
        log "enabling and starting existing systemd service"
        systemctl enable --now "${SERVICE_NAME}"
    elif [[ "${SERVICE_WAS_ACTIVE}" -eq 1 ]]; then
        log "restarting existing systemd service"
        systemctl start "${SERVICE_NAME}"
    fi
fi

log "install_dir=${INSTALL_DIR}"
log "client=${INSTALL_DIR}/veloramesh-client"
log "config=${CONFIG_PATH}"
if [[ -n "${NETWORK_NAME}" ]]; then
    if [[ -n "${NETWORK_ID:-}" ]]; then
        log "doctor=sudo \"${INSTALL_DIR}/veloramesh-client\" doctor -config \"${CONFIG_PATH}\" -id \"${NETWORK_ID}\" -discovery \"${DISCOVERY_SERVERS}\""
    else
        log "doctor=sudo \"${INSTALL_DIR}/veloramesh-client\" doctor -config \"${CONFIG_PATH}\" -network \"${NETWORK_NAME}\" -discovery \"${DISCOVERY_SERVERS}\""
    fi
else
    log "doctor=sudo \"${INSTALL_DIR}/veloramesh-client\" doctor -config \"${CONFIG_PATH}\""
fi
run_installer_self_test
commit_client_update
