# ============================================================================
# GoMyRO Kiosk Provisioning Script
# ----------------------------------------------------------------------------
# What this script does:
# - prepares a Linux machine to run as a dedicated kiosk
# - configures autologin + Chromium fullscreen
# - optionally installs Plymouth branding
# - optionally installs Tailscale and applies the station hostname
# - applies a predictable station naming convention per customer/postazione
#
# Common usage examples:
#   sudo bash scripts/provision_new_kiosk.sh
#   sudo bash scripts/provision_new_kiosk.sh --yes
#   sudo bash scripts/provision_new_kiosk.sh --yes --client dissegna --station-number 01
#   sudo bash scripts/provision_new_kiosk.sh --yes --client cruxlab --station-number 02 --url https://kiosk.example.local
#
# Post-install useful commands:
#   sudo tailscale up --ssh
#   hostnamectl status
#   tailscale status
#   systemctl status tailscaled
# ============================================================================
#!/usr/bin/env bash

# ----------------------------------------------------------------------------
# Shell safety options
# ----------------------------------------------------------------------------
set -Eeuo pipefail

# ----------------------------------------------------------------------------
# Default paths and static configuration
# ----------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
DEFAULT_KIOSK_USER="gomyro"
DEFAULT_KIOSK_URL="http://localhost:5000"
DEFAULT_PLYMOUTH_THEME_NAME="gomyro"
DEFAULT_PLYMOUTH_SOURCE_DIR="$REPO_ROOT/assets/plymouth/gomyro"
DEFAULT_CLIENT_NAME="gomyro"
DEFAULT_STATION_ROLE="kiosk"
DEFAULT_STATION_NUMBER="01"
LIGHTDM_CONF="/etc/lightdm/lightdm.conf"
LXDE_AUTOSTART_SYSTEM="/etc/xdg/lxsession/LXDE/autostart"
OPENBOX_RC="/etc/xdg/openbox/rc.xml"
TTY_OVERRIDE_DIR="/etc/systemd/system/getty@tty1.service.d"
TTY_OVERRIDE_FILE="$TTY_OVERRIDE_DIR/override.conf"

# ----------------------------------------------------------------------------
# Runtime configuration defaults (can be changed by prompts / CLI flags)
# ----------------------------------------------------------------------------
KIOSK_USER="$DEFAULT_KIOSK_USER"
KIOSK_URL="$DEFAULT_KIOSK_URL"
INSTALL_PLYMOUTH="true"
INSTALL_KIOSK="true"
CONFIGURE_AUTOLOGIN="true"
DISABLE_TTY="true"
HARDEN_OPENBOX="true"
ENABLE_UFW="false"
INSTALL_TAILSCALE="true"
APPLY_TAILSCALE_HOSTNAME="true"
ENABLE_POWER_CUT_HARDENING="true"
PLYMOUTH_THEME_NAME="$DEFAULT_PLYMOUTH_THEME_NAME"
PLYMOUTH_SOURCE_DIR="$DEFAULT_PLYMOUTH_SOURCE_DIR"
CLIENT_NAME="$DEFAULT_CLIENT_NAME"
STATION_ROLE="$DEFAULT_STATION_ROLE"
STATION_NUMBER="$DEFAULT_STATION_NUMBER"
STATION_NAME=""
ASSUME_YES="false"

# ----------------------------------------------------------------------------
# Logging helpers
# ----------------------------------------------------------------------------
log() {
  printf '\n[%s] %s\n' "INFO" "$*"
}

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

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

# ----------------------------------------------------------------------------
# Environment and shell helpers
# ----------------------------------------------------------------------------
require_root() {
  if [[ "${EUID}" -ne 0 ]]; then
    error "Run this script with sudo or as root."
    exit 1
  fi
}

command_exists() {
  command -v "$1" >/dev/null 2>&1
}

# ----------------------------------------------------------------------------
# Interactive prompt helpers
# ----------------------------------------------------------------------------
prompt_yes_no() {
  local prompt="$1"
  local default_value="${2:-y}"
  local answer

  if [[ "$ASSUME_YES" == "true" ]]; then
    [[ "$default_value" =~ ^[Yy]$ ]]
    return
  fi

  while true; do
    if [[ "$default_value" =~ ^[Yy]$ ]]; then
      read -r -p "$prompt [Y/n]: " answer || true
      answer="${answer:-Y}"
    else
      read -r -p "$prompt [y/N]: " answer || true
      answer="${answer:-N}"
    fi

    case "$answer" in
      Y|y|Yes|yes)
        return 0
        ;;
      N|n|No|no)
        return 1
        ;;
      *)
        printf 'Please answer y or n.\n'
        ;;
    esac
  done
}

prompt_value() {
  local prompt="$1"
  local default_value="${2:-}"
  local answer

  if [[ "$ASSUME_YES" == "true" ]]; then
    printf '%s' "$default_value"
    return
  fi

  read -r -p "$prompt${default_value:+ [$default_value]}: " answer || true
  printf '%s' "${answer:-$default_value}"
}

set_bool_from_prompt() {
  local var_name="$1"
  local label="$2"
  local default_value="$3"

  if prompt_yes_no "$label" "$default_value"; then
    printf -v "$var_name" 'true'
  else
    printf -v "$var_name" 'false'
  fi
}

# ----------------------------------------------------------------------------
# CLI usage and argument parsing
# ----------------------------------------------------------------------------
usage() {
  cat <<'EOF'
Usage: provision_new_kiosk.sh [options]

Options:
  --yes                       Accept defaults for all prompts
  --user <username>           Kiosk Linux user to configure
  --url <url>                 URL to open in kiosk mode
  --client <name>             Client name used to build the station name
  --station-role <role>       Station role segment used in station name
  --station-number <nn>       Station number segment used in station name
  --station-name <name>       Explicit station name override
  --skip-plymouth             Skip Plymouth installation and configuration
  --skip-kiosk                Skip kiosk package installation and startup config
  --skip-autologin            Skip LightDM autologin configuration
  --skip-disable-tty          Skip TTY hardening for tty1
  --skip-openbox-hardening    Skip Openbox keybinding hardening
  --enable-ufw                Enable UFW at the end of the script
  --skip-tailscale            Skip Tailscale installation
  --skip-tailscale-hostname   Skip applying the station name to Tailscale
  --skip-power-cut-hardening  Skip filesystem/log hardening for sudden power loss
  --plymouth-theme <name>     Plymouth theme name
  --plymouth-source <path>    Source folder containing Plymouth assets
  --help                      Show this help
EOF
}

parse_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --yes)
        ASSUME_YES="true"
        ;;
      --user)
        KIOSK_USER="${2:?Missing value for --user}"
        shift
        ;;
      --url)
        KIOSK_URL="${2:?Missing value for --url}"
        shift
        ;;
      --client)
        CLIENT_NAME="${2:?Missing value for --client}"
        shift
        ;;
      --station-role)
        STATION_ROLE="${2:?Missing value for --station-role}"
        shift
        ;;
      --station-number)
        STATION_NUMBER="${2:?Missing value for --station-number}"
        shift
        ;;
      --station-name)
        STATION_NAME="${2:?Missing value for --station-name}"
        shift
        ;;
      --skip-plymouth)
        INSTALL_PLYMOUTH="false"
        ;;
      --skip-kiosk)
        INSTALL_KIOSK="false"
        ;;
      --skip-autologin)
        CONFIGURE_AUTOLOGIN="false"
        ;;
      --skip-disable-tty)
        DISABLE_TTY="false"
        ;;
      --skip-openbox-hardening)
        HARDEN_OPENBOX="false"
        ;;
      --enable-ufw)
        ENABLE_UFW="true"
        ;;
      --skip-tailscale)
        INSTALL_TAILSCALE="false"
        ;;
      --skip-tailscale-hostname)
        APPLY_TAILSCALE_HOSTNAME="false"
        ;;
      --skip-power-cut-hardening)
        ENABLE_POWER_CUT_HARDENING="false"
        ;;
      --plymouth-theme)
        PLYMOUTH_THEME_NAME="${2:?Missing value for --plymouth-theme}"
        shift
        ;;
      --plymouth-source)
        PLYMOUTH_SOURCE_DIR="${2:?Missing value for --plymouth-source}"
        shift
        ;;
      --help|-h)
        usage
        exit 0
        ;;
      *)
        error "Unknown option: $1"
        usage
        exit 1
        ;;
    esac
    shift
  done
}

# ----------------------------------------------------------------------------
# Station naming helpers
# ----------------------------------------------------------------------------
sanitize_slug() {
  local value="$1"

  value="$(printf '%s' "$value" | tr '[:upper:]' '[:lower:]')"
  value="$(printf '%s' "$value" | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-{2,}/-/g')"
  printf '%s' "$value"
}

normalize_station_number() {
  local value="$1"

  if [[ "$value" =~ ^[0-9]+$ ]]; then
    printf '%02d' "$((10#$value))"
    return
  fi

  printf '%s' "$value"
}

compute_station_name() {
  local client_slug
  local role_slug
  local station_number_normalized

  client_slug="$(sanitize_slug "$CLIENT_NAME")"
  role_slug="$(sanitize_slug "$STATION_ROLE")"
  station_number_normalized="$(normalize_station_number "$STATION_NUMBER")"

  if [[ -n "$STATION_NAME" ]]; then
    STATION_NAME="$(sanitize_slug "$STATION_NAME")"
  else
    STATION_NAME="${client_slug}-${role_slug}-${station_number_normalized}"
  fi
}

validate_required_values() {
  if [[ -z "$(sanitize_slug "$CLIENT_NAME")" ]]; then
    error "Client name cannot be empty after normalization."
    exit 1
  fi

  if [[ -z "$(sanitize_slug "$STATION_ROLE")" ]]; then
    error "Station role cannot be empty after normalization."
    exit 1
  fi

  if [[ -z "$STATION_NUMBER" ]]; then
    error "Station number cannot be empty."
    exit 1
  fi

  if [[ -z "$STATION_NAME" ]]; then
    error "Station name cannot be empty."
    exit 1
  fi
}

# ----------------------------------------------------------------------------
# Hostname application (system + Tailscale)
# ----------------------------------------------------------------------------
apply_system_hostname() {
  local current_hostname
  current_hostname="$(hostnamectl --static status 2>/dev/null || hostname 2>/dev/null || true)"

  if [[ "$current_hostname" == "$STATION_NAME" ]]; then
    log "System hostname already set to '$STATION_NAME'."
    return
  fi

  hostnamectl set-hostname "$STATION_NAME"
  log "Applied system hostname '$STATION_NAME'."
}

apply_tailscale_hostname() {
  if [[ "$APPLY_TAILSCALE_HOSTNAME" != "true" ]]; then
    log "Skipping Tailscale hostname application by configuration."
    return
  fi

  if ! command_exists tailscale; then
    warn "Tailscale CLI not found. Skipping Tailscale hostname application."
    return
  fi

  if ! tailscale status >/dev/null 2>&1; then
    warn "Tailscale is installed but not connected yet. Run 'tailscale up' later, then apply: tailscale set --hostname=$STATION_NAME"
    return
  fi

  tailscale set --hostname="$STATION_NAME"
  log "Applied Tailscale hostname '$STATION_NAME'."
}

# ----------------------------------------------------------------------------
# Optional software installation helpers
# ----------------------------------------------------------------------------
install_tailscale() {
  if [[ "$INSTALL_TAILSCALE" != "true" ]]; then
    log "Skipping Tailscale installation by configuration."
    return
  fi

  if command_exists tailscale; then
    log "Tailscale is already installed."
    return
  fi

  if command_exists curl; then
    curl -fsSL https://tailscale.com/install.sh | sh
  elif command_exists wget; then
    wget -qO- https://tailscale.com/install.sh | sh
  else
    error "Neither curl nor wget is available. Cannot install Tailscale automatically."
    exit 1
  fi

  if command_exists systemctl; then
    systemctl enable tailscaled >/dev/null 2>&1 || true
    systemctl start tailscaled >/dev/null 2>&1 || true
  fi

  log "Installed Tailscale. Authenticate later with: tailscale up --ssh"
}

# ----------------------------------------------------------------------------
# APT package installation helper
# ----------------------------------------------------------------------------
run_apt_install() {
  local packages=("$@")
  if [[ ${#packages[@]} -eq 0 ]]; then
    return
  fi

  log "Installing packages: ${packages[*]}"
  apt-get install -y "${packages[@]}"
}

# ----------------------------------------------------------------------------
# Local kiosk user setup
# ----------------------------------------------------------------------------
ensure_user_exists() {
  if id "$KIOSK_USER" >/dev/null 2>&1; then
    log "User '$KIOSK_USER' already exists."
    return
  fi

  log "Creating kiosk user '$KIOSK_USER'."
  adduser --disabled-password --gecos "" "$KIOSK_USER"
}

# ----------------------------------------------------------------------------
# Desktop session and autologin configuration
# ----------------------------------------------------------------------------
configure_lightdm_autologin() {
  local lightdm_dir
  lightdm_dir="$(dirname "$LIGHTDM_CONF")"

  mkdir -p "$lightdm_dir"
  cat > "$LIGHTDM_CONF" <<EOF
[Seat:*]
autologin-user=$KIOSK_USER
autologin-user-timeout=0
user-session=LXDE
EOF

  log "Configured LightDM autologin for '$KIOSK_USER'."
}

configure_lxde_autostart() {
  local user_home
  user_home="$(getent passwd "$KIOSK_USER" | cut -d: -f6)"
  local user_lxsession_dir="$user_home/.config/lxsession/LXDE"
  local user_autostart_file="$user_lxsession_dir/autostart"
  local start_script="$user_home/start-kiosk.sh"

  mkdir -p "$user_lxsession_dir"

  cat > "$start_script" <<EOF
#!/usr/bin/env bash
set -e

xset -dpms
xset s off
xset s noblank

if command -v unclutter >/dev/null 2>&1; then
  unclutter -idle 0.1 -root &
fi

/usr/bin/chromium-browser \
  --kiosk \
  --noerrdialogs \
  --disable-infobars \
  --disable-session-crashed-bubble \
  --disable-restore-session-state \
  --incognito \
  --check-for-update-interval=31536000 \
  "$KIOSK_URL"
EOF

  chmod +x "$start_script"
  chown "$KIOSK_USER:$KIOSK_USER" "$start_script"

  cat > "$user_autostart_file" <<EOF
@xset s off
@xset -dpms
@xset s noblank
@/usr/bin/lxpanel --profile LXDE
@/usr/bin/pcmanfm --desktop --profile LXDE
@/usr/bin/openbox-lxde
@$start_script
EOF

  chown -R "$KIOSK_USER:$KIOSK_USER" "$user_home/.config"

  log "Configured LXDE autostart and Chromium kiosk startup."
}

configure_system_lxde_defaults() {
  mkdir -p "$(dirname "$LXDE_AUTOSTART_SYSTEM")"
  cat > "$LXDE_AUTOSTART_SYSTEM" <<'EOF'
@xset s off
@xset -dpms
@xset s noblank
EOF

  log "Configured system LXDE defaults to disable screensaver and blanking."
}

# ----------------------------------------------------------------------------
# Basic kiosk hardening
# ----------------------------------------------------------------------------
disable_tty1() {
  mkdir -p "$TTY_OVERRIDE_DIR"
  cat > "$TTY_OVERRIDE_FILE" <<'EOF'
[Service]
ExecStart=
ExecStart=-/sbin/agetty --skip-login --nonewline --noissue --noclear %I $TERM
EOF

  systemctl daemon-reload
  log "Applied tty1 override. Review if you want to fully mask getty later."
}

harden_openbox_keybindings() {
  if [[ ! -f "$OPENBOX_RC" ]]; then
    warn "Openbox config not found at $OPENBOX_RC. Skipping keybinding hardening."
    return
  fi

  python3 - "$OPENBOX_RC" <<'PY'
import sys
import xml.etree.ElementTree as ET

path = sys.argv[1]
tree = ET.parse(path)
root = tree.getroot()
ns = {'ob': 'http://openbox.org/3.4/rc'}
keyboard = root.find('ob:keyboard', ns)
if keyboard is None:
    raise SystemExit(0)

blocked = {'A-F4', 'C-A-T', 'C-A-Delete', 'W-space'}
blocked_prefixes = ('C-A-F',)

for keybind in list(keyboard.findall('ob:keybind', ns)):
    key = keybind.attrib.get('key', '')
    if key in blocked or key.startswith(blocked_prefixes):
        keyboard.remove(keybind)

tree.write(path, encoding='UTF-8', xml_declaration=True)
PY

  log "Hardened Openbox keybindings."
}

# ----------------------------------------------------------------------------
# Plymouth branding setup
# ----------------------------------------------------------------------------
install_plymouth_theme() {
  local target_dir="/usr/share/plymouth/themes/$PLYMOUTH_THEME_NAME"
  local theme_file="$target_dir/$PLYMOUTH_THEME_NAME.plymouth"
  local script_file="$target_dir/$PLYMOUTH_THEME_NAME.script"

  if [[ ! -d "$PLYMOUTH_SOURCE_DIR" ]]; then
    warn "Plymouth source directory not found: $PLYMOUTH_SOURCE_DIR"
    warn "Create it with logo.png and any additional assets before running Plymouth setup."
    return
  fi

  mkdir -p "$target_dir"
  cp -R "$PLYMOUTH_SOURCE_DIR"/. "$target_dir"/

  if [[ ! -f "$theme_file" ]]; then
    cat > "$theme_file" <<EOF
[Plymouth Theme]
Name=GoMyRO
Description=GoMyRO Boot Splash
ModuleName=script

[script]
ImageDir=$target_dir
ScriptFile=$script_file
EOF
  fi

  if [[ ! -f "$script_file" ]]; then
    cat > "$script_file" <<'EOF'
logo_image = Image("logo.png");
screen_width = Window.GetWidth();
screen_height = Window.GetHeight();
logo_sprite = Sprite(logo_image);
logo_sprite.SetPosition(
  (screen_width - logo_image.GetWidth()) / 2,
  (screen_height - logo_image.GetHeight()) / 2
);
EOF
  fi

  update-alternatives --install /usr/share/plymouth/themes/default.plymouth default.plymouth "$theme_file" 100
  update-alternatives --set default.plymouth "$theme_file"
  update-initramfs -u

  log "Installed and activated Plymouth theme '$PLYMOUTH_THEME_NAME'."
}

# ----------------------------------------------------------------------------
# Filesystem / logging hardening for sudden power loss
# ----------------------------------------------------------------------------
configure_journald_volatile() {
  local journald_conf="/etc/systemd/journald.conf"

  if [[ ! -f "$journald_conf" ]]; then
    warn "journald config not found at $journald_conf. Skipping volatile journal setup."
    return
  fi

  if grep -q '^Storage=volatile$' "$journald_conf"; then
    log "journald is already configured with Storage=volatile."
  elif grep -q '^#Storage=' "$journald_conf"; then
    sed -i 's/^#Storage=.*/Storage=volatile/' "$journald_conf"
    log "Updated journald storage mode to volatile."
  elif grep -q '^Storage=' "$journald_conf"; then
    sed -i 's/^Storage=.*/Storage=volatile/' "$journald_conf"
    log "Replaced existing journald storage mode with volatile."
  else
    printf '\nStorage=volatile\n' >> "$journald_conf"
    log "Appended Storage=volatile to journald config."
  fi

  systemctl restart systemd-journald
  log "Restarted systemd-journald."
}

configure_power_cut_hardening() {
  local fstab_file="/etc/fstab"
  local sysctl_dropin_dir="/etc/sysctl.d"
  local sysctl_dropin_file="$sysctl_dropin_dir/60-gomyro-kiosk-powercut.conf"
  local tmpfs_entry='tmpfs /tmp tmpfs defaults,noatime,nosuid,nodev,size=100m 0 0'

  if [[ "$ENABLE_POWER_CUT_HARDENING" != "true" ]]; then
    log "Skipping power-cut hardening by configuration."
    return
  fi

  configure_journald_volatile

  if grep -qE '^[^#].*\s/tmp\s+tmpfs\s' "$fstab_file"; then
    log "/tmp is already mounted as tmpfs in /etc/fstab."
  else
    printf '\n%s\n' "$tmpfs_entry" >> "$fstab_file"
    log "Added tmpfs mount for /tmp to /etc/fstab."
  fi

  mkdir -p "$sysctl_dropin_dir"
  cat > "$sysctl_dropin_file" <<'EOF'
vm.dirty_writeback_centisecs = 1500
vm.dirty_expire_centisecs = 1500
EOF

  sysctl --system >/dev/null
  log "Applied conservative writeback settings for sudden power loss resilience."
}

# ----------------------------------------------------------------------------
# Optional firewall setup
# ----------------------------------------------------------------------------
enable_ufw_if_requested() {
  if [[ "$ENABLE_UFW" != "true" ]]; then
    return
  fi

  if ! command_exists ufw; then
    run_apt_install ufw
  fi

  ufw --force enable
  log "Enabled UFW."
}

# ----------------------------------------------------------------------------
# Interactive configuration flow
# ----------------------------------------------------------------------------
interactive_configuration() {
  if [[ "$ASSUME_YES" == "true" ]]; then
    compute_station_name
    validate_required_values
    return
  fi

  printf '\n=== GoMyRO kiosk provisioning ===\n'

  while true; do
    CLIENT_NAME="$(prompt_value "Client name" "$CLIENT_NAME")"
    STATION_ROLE="$(prompt_value "Station role" "$STATION_ROLE")"
    STATION_NUMBER="$(prompt_value "Station number" "$STATION_NUMBER")"

    compute_station_name

    printf '\nGenerated station name: %s\n' "$STATION_NAME"
    if prompt_yes_no "Confirm generated station name?" "y"; then
      break
    fi
  done

  if prompt_yes_no "Override generated station name manually?" "n"; then
    STATION_NAME="$(prompt_value "Station name" "$STATION_NAME")"
    STATION_NAME="$(sanitize_slug "$STATION_NAME")"
  fi

  validate_required_values

  KIOSK_USER="$(prompt_value "Kiosk user" "$KIOSK_USER")"
  KIOSK_URL="$(prompt_value "Kiosk URL" "$KIOSK_URL")"
  set_bool_from_prompt INSTALL_KIOSK "Install Chromium kiosk packages and startup config?" "y"
  set_bool_from_prompt CONFIGURE_AUTOLOGIN "Configure LightDM autologin?" "y"
  set_bool_from_prompt DISABLE_TTY "Apply tty1 hardening?" "y"
  set_bool_from_prompt HARDEN_OPENBOX "Harden Openbox keybindings?" "y"
  set_bool_from_prompt INSTALL_PLYMOUTH "Install and configure Plymouth?" "y"

  if [[ "$INSTALL_PLYMOUTH" == "true" ]]; then
    PLYMOUTH_THEME_NAME="$(prompt_value "Plymouth theme name" "$PLYMOUTH_THEME_NAME")"
    PLYMOUTH_SOURCE_DIR="$(prompt_value "Plymouth source directory" "$PLYMOUTH_SOURCE_DIR")"
  fi

  set_bool_from_prompt ENABLE_UFW "Enable UFW firewall at the end?" "n"
  set_bool_from_prompt INSTALL_TAILSCALE "Install Tailscale?" "y"
  set_bool_from_prompt APPLY_TAILSCALE_HOSTNAME "Apply station name to Tailscale when available?" "y"
  set_bool_from_prompt ENABLE_POWER_CUT_HARDENING "Enable power-cut hardening (volatile logs, /tmp tmpfs, safer writeback)?" "y"
}

# ----------------------------------------------------------------------------
# Final configuration summary
# ----------------------------------------------------------------------------
print_summary() {
  cat <<EOF

=== Provisioning summary ===
Client name:             $CLIENT_NAME
Station role:            $STATION_ROLE
Station number:          $STATION_NUMBER
Station name:            $STATION_NAME
User:                    $KIOSK_USER
Kiosk URL:               $KIOSK_URL
Install kiosk packages:  $INSTALL_KIOSK
Configure autologin:     $CONFIGURE_AUTOLOGIN
Apply tty1 hardening:    $DISABLE_TTY
Harden Openbox:          $HARDEN_OPENBOX
Install Plymouth:        $INSTALL_PLYMOUTH
Plymouth theme:          $PLYMOUTH_THEME_NAME
Plymouth assets dir:     $PLYMOUTH_SOURCE_DIR
Enable UFW:              $ENABLE_UFW
Install Tailscale:       $INSTALL_TAILSCALE
Apply Tailscale name:    $APPLY_TAILSCALE_HOSTNAME
Power-cut hardening:     $ENABLE_POWER_CUT_HARDENING
EOF
}

# ----------------------------------------------------------------------------
# Main execution flow
# ----------------------------------------------------------------------------
main() {
  require_root
  parse_args "$@"
  compute_station_name
  validate_required_values
  interactive_configuration
  print_summary

  if [[ "$ASSUME_YES" != "true" ]]; then
    prompt_yes_no "Continue with provisioning?" "y" || {
      warn "Provisioning cancelled."
      exit 0
    }
  fi

  # Refresh package metadata before installing anything
  log "Updating apt package index."
  apt-get update

  # Install the minimal graphical stack required for kiosk mode
  run_apt_install lightdm lxde-core openbox xorg xinit x11-xserver-utils

  # Prepare identity and remote-access naming
  ensure_user_exists
  install_tailscale
  apply_system_hostname
  apply_tailscale_hostname
  log "Station name resolved to '$STATION_NAME'."

  # Install and configure the browser kiosk experience
  if [[ "$INSTALL_KIOSK" == "true" ]]; then
    run_apt_install chromium-browser unclutter xdotool
    configure_system_lxde_defaults
    configure_lxde_autostart
  fi

  # Apply desktop autologin and local hardening choices
  if [[ "$CONFIGURE_AUTOLOGIN" == "true" ]]; then
    configure_lightdm_autologin
  fi

  if [[ "$DISABLE_TTY" == "true" ]]; then
    disable_tty1
  fi

  if [[ "$HARDEN_OPENBOX" == "true" ]]; then
    harden_openbox_keybindings
  fi

  # Install and activate branded boot splash if requested
  if [[ "$INSTALL_PLYMOUTH" == "true" ]]; then
    run_apt_install plymouth plymouth-themes
    install_plymouth_theme
  fi

  # Reduce disk writes and improve resilience against sudden power cuts
  configure_power_cut_hardening

  # Enable firewall only at the very end, after setup is complete
  enable_ufw_if_requested

  log "Provisioning completed. Reboot the machine to validate kiosk startup and splash screen."
}

main "$@"