#!/bin/sh
set -eu

CONFIG_PATH="/etc/photobooth/config.yml"
FALLBACK_URL="http://127.0.0.1:1610"
KIOSK_WAITING_SOURCE="/usr/share/photobooth/kiosk-waiting.html"
KIOSK_WAITING_PAGE="/var/lib/photobooth/kiosk-waiting.html"
KIOSK_BROWSER_CONFIG="/var/lib/photobooth/kiosk-browser"
KIOSK_START_BIN="/usr/bin/photobooth"
KIOSK_START_COMMAND="$KIOSK_START_BIN kiosk start"

print_help() {
  cat <<'EOF'
photobooth help
  Show all available commands with a short description.

photobooth config-path
  Print the path to the active photobooth config file.

photobooth config-show
  Print the current config file to the terminal.

photobooth edit-config
  Open the config file in nano when available, otherwise fall back to $EDITOR.

photobooth fix-gphoto2-automount
  Stop active gvfs gphoto2 automount processes and mask the volume-monitor service for future boots.

photobooth kiosk status
  Reserved for a future kiosk status command (not implemented yet).

photobooth kiosk install --user <linux-user> [--url <url>] [--browser <browser>]
  Install Raspberry Pi OS kiosk autologin + browser fullscreen startup for the given desktop user.
  Without --url, the command uses server.bind/server.port from config.yml and falls back to the local default URL.

photobooth kiosk start
  Start the kiosk browser as the desktop user. This command does not require sudo.

photobooth kiosk fix-waiting-page
  Rewrite the global kiosk waiting page with the target URL from config.yml.
  Uses server.bind/server.port from config.yml and falls back to the local default URL.
EOF
}

require_root() {
  if [ "$(id -u)" -ne 0 ]; then
    echo "This command must be run as root." >&2
    exit 1
  fi
}

ensure_config_exists() {
  if [ ! -f "$CONFIG_PATH" ]; then
    echo "Config file not found: $CONFIG_PATH" >&2
    exit 1
  fi
}

ensure_supported_os() {
  if [ ! -r /etc/os-release ]; then
    echo "Unsupported OS: /etc/os-release not found." >&2
    exit 1
  fi

  if ! grep -qi "raspbian\|Raspberry Pi OS" /etc/os-release \
    && ! (grep -qi '^ID="\?debian"\?$' /etc/os-release \
      && grep -qi '^VERSION_CODENAME="\?trixie"\?$' /etc/os-release); then
    echo "Unsupported OS: kiosk install currently supports Raspberry Pi OS (including Debian 13/Trixie images) only." >&2
    exit 1
  fi

  if ! command -v raspi-config >/dev/null 2>&1; then
    echo "Unsupported OS: raspi-config is required for kiosk install." >&2
    exit 1
  fi
}

open_config() {
  ensure_config_exists

  if command -v nano >/dev/null 2>&1; then
    exec nano "$CONFIG_PATH"
  fi

  if [ -n "${EDITOR:-}" ] && command -v "$EDITOR" >/dev/null 2>&1; then
    exec "$EDITOR" "$CONFIG_PATH"
  fi

  echo "nano is not installed and \$EDITOR is not set to a valid editor." >&2
  echo "Install nano with: sudo apt install nano" >&2
  exit 1
}

show_config() {
  ensure_config_exists
  cat "$CONFIG_PATH"
}

fix_gphoto2_automount() {
  require_root

  if ! command -v systemctl >/dev/null 2>&1; then
    echo "systemctl is required to manage gvfs gphoto2 automount services." >&2
    exit 1
  fi

  UNIT_NAME="gvfs-gphoto2-volume-monitor.service"
  MASKED_ANY=0

  echo "Applying gphoto2 automount fix for: $UNIT_NAME"

  if command -v pkill >/dev/null 2>&1; then
    pkill -f gvfs-gphoto2-volume-monitor || true
  fi

  if systemctl stop "$UNIT_NAME" >/dev/null 2>&1; then
    echo "Stopped system unit: $UNIT_NAME"
  else
    echo "System unit was not running or is not available: $UNIT_NAME"
  fi

  if systemctl mask "$UNIT_NAME" >/dev/null 2>&1; then
    echo "Masked system unit: $UNIT_NAME"
    MASKED_ANY=1
  fi

  if systemctl --global mask "$UNIT_NAME" >/dev/null 2>&1; then
    echo "Masked global user unit: $UNIT_NAME"
    MASKED_ANY=1
  fi

  if [ "$MASKED_ANY" -eq 0 ]; then
    echo "Could not mask $UNIT_NAME with systemctl." >&2
    exit 1
  fi

  echo "gphoto2 automount fix applied. Reboot or log in again to pick up the change."
}

write_managed_block() {
  TARGET_PATH="$1"
  BLOCK_PATH="$2"
  START_MARKER="# >>> photobooth kiosk >>>"
  END_MARKER="# <<< photobooth kiosk <<<"
  TMP_PATH=$(mktemp)

  if [ -f "$TARGET_PATH" ]; then
    awk -v start="$START_MARKER" -v end="$END_MARKER" '
      $0 == start { skip = 1; next }
      $0 == end { skip = 0; next }
      !skip { print }
    ' "$TARGET_PATH" > "$TMP_PATH"
  else
    : > "$TMP_PATH"
  fi

  cat "$BLOCK_PATH" >> "$TMP_PATH"
  install -m 0644 "$TMP_PATH" "$TARGET_PATH"
  rm -f "$TMP_PATH"
}

resolve_browser_package() {
  REQUESTED_BROWSER="${1:-}"

  is_installable() {
    apt-cache policy "$1" 2>/dev/null | grep -q '^  Candidate: ' \
      && ! apt-cache policy "$1" 2>/dev/null | grep -q '^  Candidate: (none)$'
  }

  case "$REQUESTED_BROWSER" in
    ""|chromium)
      if is_installable chromium; then
        printf '%s\n' chromium
        return 0
      fi
      if [ -z "$REQUESTED_BROWSER" ] && is_installable chromium-browser; then
        printf '%s\n' chromium-browser
        return 0
      fi
      ;;
    chromium-browser)
      if is_installable chromium-browser; then
        printf '%s\n' chromium-browser
        return 0
      fi
      ;;
  esac

  if [ -n "$REQUESTED_BROWSER" ]; then
    echo "Unsupported browser: $REQUESTED_BROWSER. Supported values are chromium and chromium-browser." >&2
  else
    echo "Unsupported OS: neither chromium nor chromium-browser is installable via apt." >&2
  fi
  exit 1
}

resolve_desktop_dir() {
  USER_HOME="$1"
  USER_DIRS_FILE="$USER_HOME/.config/user-dirs.dirs"
  DESKTOP_DIR="$USER_HOME/Desktop"

  if [ -f "$USER_DIRS_FILE" ]; then
    DESKTOP_SETTING=$(awk -F= '/^XDG_DESKTOP_DIR=/{print $2}' "$USER_DIRS_FILE" | tail -n1 | tr -d '"')
    if [ -n "$DESKTOP_SETTING" ]; then
      case "$DESKTOP_SETTING" in
        \$HOME/*)
          DESKTOP_DIR="$USER_HOME/${DESKTOP_SETTING#\$HOME/}"
          ;;
        "$USER_HOME"/*)
          DESKTOP_DIR="$DESKTOP_SETTING"
          ;;
      esac
    fi
  fi

  printf '%s\n' "$DESKTOP_DIR"
}

escape_js_string() {
  printf '%s' "$1" | sed \
    -e 's/\\/\\\\/g' \
    -e 's/"/\\"/g' \
    -e 's/&/\\u0026/g' \
    -e 's/</\\u003C/g' \
    -e 's/>/\\u003E/g'
}

escape_sed_replacement() {
  printf '%s' "$1" | sed -e 's/[\\&|]/\\&/g'
}

read_config_section_scalar() {
  section="$1"
  key="$2"

  if [ ! -f "$CONFIG_PATH" ]; then
    return 1
  fi

  in_section=0

  while IFS= read -r line || [ -n "$line" ]; do
    trimmed_line=$(printf '%s' "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')

    case "$trimmed_line" in
      ''|\#*)
        continue
        ;;
    esac

    if [ "$in_section" -eq 0 ]; then
      if [ "$trimmed_line" = "$section:" ]; then
        in_section=1
      fi
      continue
    fi

    case "$line" in
      [![:space:]]*)
        break
        ;;
    esac

    case "$trimmed_line" in
      "$key":*)
        value=${trimmed_line#"$key":}
        value=$(printf '%s' "$value" | sed -e 's/[[:space:]]*#.*$//' -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')

        case "$value" in
          \"*\")
            value=${value#\"}
            value=${value%\"}
            ;;
          \'*\')
            value=${value#\'}
            value=${value%\'}
            ;;
        esac

        printf '%s\n' "$value"
        return 0
        ;;
    esac
  done < "$CONFIG_PATH"

  return 1
}

normalize_kiosk_host() {
  host="$1"

  case "$host" in
    0.0.0.0|::|[::])
      printf '%s\n' "127.0.0.1"
      ;;
    *:*)
      case "$host" in
        \[*\])
          printf '%s\n' "$host"
          ;;
        *)
          printf '[%s]\n' "$host"
          ;;
      esac
      ;;
    *)
      printf '%s\n' "$host"
      ;;
  esac
}

resolve_kiosk_url_from_config() {
  bind=$(read_config_section_scalar server bind || true)
  port=$(read_config_section_scalar server port || true)

  if [ -z "$bind" ] || [ -z "$port" ]; then
    return 1
  fi

  case "$port" in
    *[!0-9]*|'')
      return 1
      ;;
  esac

  host=$(normalize_kiosk_host "$bind")
  if [ -z "$host" ]; then
    return 1
  fi

  printf 'http://%s:%s\n' "$host" "$port"
}

resolve_kiosk_url() {
  requested_url="${1:-}"

  if [ -n "$requested_url" ]; then
    printf '%s\n' "$requested_url"
    return 0
  fi

  configured_url=$(resolve_kiosk_url_from_config || true)
  if [ -n "$configured_url" ]; then
    printf '%s\n' "$configured_url"
    return 0
  fi

  printf '%s\n' "$FALLBACK_URL"
}

resolve_kiosk_user_home() {
  KIOSK_USER="$1"

  if ! id "$KIOSK_USER" >/dev/null 2>&1; then
    echo "Linux user not found: $KIOSK_USER" >&2
    exit 1
  fi

  USER_HOME=$(getent passwd "$KIOSK_USER" | cut -d: -f6)
  if [ -z "$USER_HOME" ] || [ ! -d "$USER_HOME" ]; then
    echo "Could not determine a valid home directory for user: $KIOSK_USER" >&2
    exit 1
  fi

  printf '%s\n' "$USER_HOME"
}

render_kiosk_waiting_page() {
  KIOSK_URL="$1"
  KIOSK_WAITING_DIR=$(dirname "$KIOSK_WAITING_PAGE")
  KIOSK_URL_JS=$(escape_js_string "$KIOSK_URL")
  KIOSK_URL_JS_SED=$(escape_sed_replacement "$KIOSK_URL_JS")
  TMP_PATH=$(mktemp)

  if [ ! -f "$KIOSK_WAITING_SOURCE" ]; then
    echo "Kiosk waiting-page HTML not found: $KIOSK_WAITING_SOURCE" >&2
    rm -f "$TMP_PATH"
    exit 1
  fi

  if ! grep -q '__KIOSK_URL__' "$KIOSK_WAITING_SOURCE"; then
    echo "Kiosk waiting-page template does not contain the configured target URL marker." >&2
    rm -f "$TMP_PATH"
    exit 1
  fi

  sed "s|__KIOSK_URL__|$KIOSK_URL_JS_SED|g" "$KIOSK_WAITING_SOURCE" > "$TMP_PATH"
  install -d -m 0755 "$KIOSK_WAITING_DIR"

  if id photobooth-service >/dev/null 2>&1 && getent group photobooth-service >/dev/null 2>&1; then
    install -o photobooth-service -g photobooth-service -m 0644 "$TMP_PATH" "$KIOSK_WAITING_PAGE"
  else
    install -m 0644 "$TMP_PATH" "$KIOSK_WAITING_PAGE"
  fi

  rm -f "$TMP_PATH"

  printf '%s\n' "$KIOSK_WAITING_PAGE"
}

write_kiosk_browser_config() {
  BROWSER_PACKAGE="$1"
  KIOSK_BROWSER_DIR=$(dirname "$KIOSK_BROWSER_CONFIG")
  TMP_PATH=$(mktemp)

  printf '%s\n' "$BROWSER_PACKAGE" > "$TMP_PATH"
  install -d -m 0755 "$KIOSK_BROWSER_DIR"
  install -m 0644 "$TMP_PATH" "$KIOSK_BROWSER_CONFIG"
  rm -f "$TMP_PATH"
}

fix_kiosk_waiting_page() {
  require_root

  if [ "$#" -gt 0 ]; then
    echo "Usage: photobooth kiosk fix-waiting-page" >&2
    exit 1
  fi

  KIOSK_URL=$(resolve_kiosk_url "")
  KIOSK_WAITING_PAGE=$(render_kiosk_waiting_page "$KIOSK_URL")

  echo "Kiosk waiting page fixed from global config."
  echo "Configured URL: $KIOSK_URL"
  echo "Updated waiting page: $KIOSK_WAITING_PAGE"
}

resolve_current_user_home() {
  if [ -n "${HOME:-}" ] && [ -d "$HOME" ]; then
    printf '%s\n' "$HOME"
    return 0
  fi

  CURRENT_USER=$(id -un)
  USER_HOME=$(getent passwd "$CURRENT_USER" | cut -d: -f6)
  if [ -z "$USER_HOME" ] || [ ! -d "$USER_HOME" ]; then
    echo "Could not determine a valid home directory for the current user." >&2
    exit 1
  fi

  printf '%s\n' "$USER_HOME"
}

read_kiosk_browser_config() {
  if [ ! -f "$KIOSK_BROWSER_CONFIG" ]; then
    return 1
  fi

  BROWSER_PACKAGE=$(sed -n '1p' "$KIOSK_BROWSER_CONFIG")
  case "$BROWSER_PACKAGE" in
    chromium|chromium-browser)
      printf '%s\n' "$BROWSER_PACKAGE"
      return 0
      ;;
    "")
      return 1
      ;;
    *)
      echo "Ignoring invalid kiosk browser config: $KIOSK_BROWSER_CONFIG" >&2
      return 1
      ;;
  esac
}

detect_kiosk_browser_package() {
  if [ -x /usr/bin/chromium ]; then
    printf '%s\n' chromium
    return 0
  fi

  if [ -x /usr/bin/chromium-browser ]; then
    printf '%s\n' chromium-browser
    return 0
  fi

  echo "Browser binary not found. Run 'sudo photobooth kiosk install --user <linux-user>' first." >&2
  exit 1
}

resolve_kiosk_browser_binary() {
  BROWSER_PACKAGE="$1"

  case "$BROWSER_PACKAGE" in
    chromium|chromium-browser)
      BROWSER_BIN="/usr/bin/$BROWSER_PACKAGE"
      ;;
    *)
      echo "Unsupported kiosk browser package: $BROWSER_PACKAGE" >&2
      exit 1
      ;;
  esac

  if [ ! -x "$BROWSER_BIN" ]; then
    echo "Browser binary not found for package: $BROWSER_PACKAGE" >&2
    exit 1
  fi

  printf '%s\n' "$BROWSER_BIN"
}

start_kiosk() {
  if [ "$#" -gt 0 ]; then
    echo "Usage: photobooth kiosk start" >&2
    exit 1
  fi

  if [ "$(id -u)" -eq 0 ]; then
    echo "photobooth kiosk start must be run as the desktop user, not with sudo." >&2
    exit 1
  fi

  if [ ! -f "$KIOSK_WAITING_PAGE" ]; then
    echo "Kiosk waiting page not found: $KIOSK_WAITING_PAGE" >&2
    echo "Run 'sudo photobooth kiosk install --user <linux-user>' first." >&2
    exit 1
  fi

  USER_HOME=$(resolve_current_user_home)
  BROWSER_PACKAGE=$(read_kiosk_browser_config || true)
  if [ -z "$BROWSER_PACKAGE" ]; then
    BROWSER_PACKAGE=$(detect_kiosk_browser_package)
  fi

  BROWSER_BIN=$(resolve_kiosk_browser_binary "$BROWSER_PACKAGE")
  WAITING_PAGE_URL="file://$KIOSK_WAITING_PAGE"
  LOCK_DIR="${XDG_RUNTIME_DIR:-$USER_HOME/.cache}"
  LOCK_PATH="${LOCK_DIR}/photobooth-kiosk.lock"

  if ! command -v flock >/dev/null 2>&1; then
    echo "flock is required to start the kiosk browser safely." >&2
    exit 1
  fi

  mkdir -p "$LOCK_DIR"
  exec 9>"$LOCK_PATH"
  if ! flock -n 9; then
    exit 0
  fi

  exec "$BROWSER_BIN" \
    --kiosk \
    --incognito \
    --noerrdialogs \
    --disable-infobars \
    --disable-session-crashed-bubble \
    --no-first-run \
    --enable-features=OverlayScrollbar \
    --start-maximized \
    "$WAITING_PAGE_URL"
}

install_kiosk() {
  require_root
  ensure_supported_os

  KIOSK_USER=""
  KIOSK_URL=""
  KIOSK_BROWSER="chromium"

  while [ "$#" -gt 0 ]; do
    case "$1" in
      --user)
        [ "$#" -ge 2 ] || { echo "Missing value for --user" >&2; exit 1; }
        KIOSK_USER="$2"
        shift 2
        ;;
      --url)
        [ "$#" -ge 2 ] || { echo "Missing value for --url" >&2; exit 1; }
        KIOSK_URL="$2"
        shift 2
        ;;
      --browser)
        [ "$#" -ge 2 ] || { echo "Missing value for --browser" >&2; exit 1; }
        KIOSK_BROWSER="$2"
        shift 2
        ;;
      *)
        echo "Unknown kiosk install option: $1" >&2
        exit 1
        ;;
    esac
  done

  if [ -z "$KIOSK_USER" ]; then
    echo "Usage: photobooth kiosk install --user <linux-user> [--url <url>] [--browser <browser>]" >&2
    exit 1
  fi

  KIOSK_URL=$(resolve_kiosk_url "$KIOSK_URL")
  USER_HOME=$(resolve_kiosk_user_home "$KIOSK_USER")

  apt update

  BROWSER_PACKAGE=$(resolve_browser_package "$KIOSK_BROWSER")

  DEBIAN_FRONTEND=noninteractive apt install -y \
    "$BROWSER_PACKAGE" \
    ca-certificates \
    nano

  USER_GROUP=$(id -gn "$KIOSK_USER")
  DESKTOP_DIR=$(resolve_desktop_dir "$USER_HOME")
  AUTOSTART_DESKTOP_FILE="$USER_HOME/.config/autostart/photobooth-kiosk.desktop"
  DESKTOP_LAUNCHER_FILE="$DESKTOP_DIR/photobooth-kiosk.desktop"
  KIOSK_WAITING_PAGE=$(render_kiosk_waiting_page "$KIOSK_URL")
  write_kiosk_browser_config "$BROWSER_PACKAGE"

  install -d -o "$KIOSK_USER" -g "$USER_GROUP" -m 0755 "$USER_HOME/.config/autostart"
  install -d -o "$KIOSK_USER" -g "$USER_GROUP" -m 0755 "$USER_HOME/.config/labwc"
  install -d -o "$KIOSK_USER" -g "$USER_GROUP" -m 0755 "$USER_HOME/.cache"
  install -d -o "$KIOSK_USER" -g "$USER_GROUP" -m 0755 "$DESKTOP_DIR"

  cat > "$AUTOSTART_DESKTOP_FILE" <<EOF
[Desktop Entry]
Type=Application
Name=Photobooth Kiosk
TryExec=$KIOSK_START_BIN
Exec=$KIOSK_START_COMMAND
Terminal=false
X-GNOME-Autostart-enabled=true
EOF
  chmod 0644 "$AUTOSTART_DESKTOP_FILE"
  chown "$KIOSK_USER:$USER_GROUP" "$AUTOSTART_DESKTOP_FILE"

  cat > "$DESKTOP_LAUNCHER_FILE" <<EOF
[Desktop Entry]
Type=Application
Version=1.0
Name=Photobooth Kiosk
Comment=Restart the photobooth kiosk browser
TryExec=$KIOSK_START_BIN
Exec=$KIOSK_START_COMMAND
Terminal=false
Icon=web-browser
Categories=Utility;
StartupNotify=false
EOF
  chmod 0755 "$DESKTOP_LAUNCHER_FILE"
  chown "$KIOSK_USER:$USER_GROUP" "$DESKTOP_LAUNCHER_FILE"

  LABWC_BLOCK=$(mktemp)
  cat > "$LABWC_BLOCK" <<EOF
# >>> photobooth kiosk >>>
$KIOSK_START_COMMAND &
# <<< photobooth kiosk <<<
EOF
  write_managed_block "$USER_HOME/.config/labwc/autostart" "$LABWC_BLOCK"
  rm -f "$LABWC_BLOCK"

  chown -R "$KIOSK_USER:$USER_GROUP" "$USER_HOME/.config/autostart" "$USER_HOME/.config/labwc" "$USER_HOME/.cache"

  raspi-config nonint do_boot_behaviour B4

  echo "Kiosk mode files installed for user: $KIOSK_USER"
  echo "Configured URL: $KIOSK_URL"
  echo "Startup waiting page: $KIOSK_WAITING_PAGE"
  echo "Configured browser package: $BROWSER_PACKAGE"
  echo "Kiosk start command: $KIOSK_START_COMMAND"
  echo "Desktop launcher: $DESKTOP_LAUNCHER_FILE"
  echo "Installed startup hooks for current Raspberry Pi OS Desktop (labwc) plus desktop autostart fallback."
  echo "Desktop autologin has been enabled. Reboot the system to test the kiosk startup."
}

COMMAND="${1:-help}"
case "$COMMAND" in
  help|-h|--help)
    print_help
    ;;
  config-path)
    printf '%s\n' "$CONFIG_PATH"
    ;;
  edit-config)
    open_config
    ;;
  config-show)
    show_config
    ;;
  fix-gphoto2-automount)
    fix_gphoto2_automount
    ;;
  kiosk)
    SUBCOMMAND="${2:-}"
    case "$SUBCOMMAND" in
      status)
        echo "photobooth kiosk status is not implemented yet."
        exit 1
        ;;
      install)
        shift 2
        install_kiosk "$@"
        ;;
      start)
        shift 2
        start_kiosk "$@"
        ;;
      fix-waiting-page)
        shift 2
        fix_kiosk_waiting_page "$@"
        ;;
      *)
        echo "Unknown kiosk subcommand: ${SUBCOMMAND:-<missing>}" >&2
        echo "Run 'photobooth help' for usage." >&2
        exit 1
        ;;
    esac
    ;;
  '')
    print_help
    ;;
  *)
    echo "Unknown command: $COMMAND" >&2
    echo "Run 'photobooth help' for usage." >&2
    exit 1
    ;;
esac
