#!/bin/sh
set -eu

CONFIG_PATH="/etc/photobooth/config.yml"
FALLBACK_URL="http://127.0.0.1:1610"

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 set-url --user <linux-user> [--url <url>]
  Rewrite the kiosk waiting page for the given desktop user with the configured target URL.
  Without --url, the command 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"
}

resolve_kiosk_url_metadata_path() {
  USER_HOME="$1"
  printf '%s\n' "$USER_HOME/.config/photobooth/kiosk-url"
}

persist_kiosk_url() {
  KIOSK_USER="$1"
  KIOSK_URL="$2"
  USER_HOME="$3"
  USER_GROUP=$(id -gn "$KIOSK_USER")
  KIOSK_URL_PATH=$(resolve_kiosk_url_metadata_path "$USER_HOME")
  KIOSK_URL_DIR=$(dirname "$KIOSK_URL_PATH")
  TMP_PATH=$(mktemp)

  install -d -o "$KIOSK_USER" -g "$USER_GROUP" -m 0755 "$KIOSK_URL_DIR"
  printf '%s\n' "$KIOSK_URL" > "$TMP_PATH"
  install -o "$KIOSK_USER" -g "$USER_GROUP" -m 0644 "$TMP_PATH" "$KIOSK_URL_PATH"
  rm -f "$TMP_PATH"

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

render_kiosk_waiting_page() {
  KIOSK_USER="$1"
  KIOSK_URL="$2"
  USER_HOME="$3"
  USER_GROUP=$(id -gn "$KIOSK_USER")
  KIOSK_WAITING_SOURCE="/usr/share/photobooth/kiosk-waiting.html"
  KIOSK_WAITING_PAGE="$USER_HOME/.local/share/photobooth/kiosk-waiting.html"
  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

  install -d -o "$KIOSK_USER" -g "$USER_GROUP" -m 0755 "$USER_HOME/.local/share/photobooth"
  sed "s|__KIOSK_URL__|$KIOSK_URL_JS_SED|g" "$KIOSK_WAITING_SOURCE" > "$TMP_PATH"
  install -o "$KIOSK_USER" -g "$USER_GROUP" -m 0644 "$TMP_PATH" "$KIOSK_WAITING_PAGE"
  rm -f "$TMP_PATH"

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

set_kiosk_url() {
  require_root

  KIOSK_USER=""
  KIOSK_URL=""

  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
        ;;
      *)
        echo "Unknown kiosk set-url option: $1" >&2
        exit 1
        ;;
    esac
  done

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

  KIOSK_URL=$(resolve_kiosk_url "$KIOSK_URL")
  USER_HOME=$(resolve_kiosk_user_home "$KIOSK_USER")
  KIOSK_WAITING_PAGE=$(render_kiosk_waiting_page "$KIOSK_USER" "$KIOSK_URL" "$USER_HOME")
  KIOSK_URL_PATH=$(persist_kiosk_url "$KIOSK_USER" "$KIOSK_URL" "$USER_HOME")

  echo "Kiosk waiting page URL updated for user: $KIOSK_USER"
  echo "Configured URL: $KIOSK_URL"
  echo "Updated waiting page: $KIOSK_WAITING_PAGE"
  echo "Stored kiosk URL metadata: $KIOSK_URL_PATH"
}

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")
  KIOSK_WAITING_PAGE=$(render_kiosk_waiting_page "$KIOSK_USER" "$KIOSK_URL" "$USER_HOME")
  KIOSK_URL_PATH=$(persist_kiosk_url "$KIOSK_USER" "$KIOSK_URL" "$USER_HOME")
  KIOSK_WAITING_PAGE_URL="file://$KIOSK_WAITING_PAGE"

  install -d -o "$KIOSK_USER" -g "$USER_GROUP" -m 0755 "$USER_HOME/.local/bin"
  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 > "$USER_HOME/.local/bin/photobooth-kiosk.sh" <<EOF
#!/usr/bin/env bash
set -euo pipefail

BROWSER_PACKAGE="${BROWSER_PACKAGE}"
WAITING_PAGE_URL="${KIOSK_WAITING_PAGE_URL}"
LOCK_DIR="\${XDG_RUNTIME_DIR:-$USER_HOME/.cache}"
LOCK_PATH="\${LOCK_DIR}/photobooth-kiosk.lock"

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

case "\$BROWSER_PACKAGE" in
  chromium)
    BROWSER_BIN="/usr/bin/chromium"
    ;;
  chromium-browser)
    BROWSER_BIN="/usr/bin/chromium-browser"
    ;;
  *)
    BROWSER_BIN="/usr/bin/\$BROWSER_PACKAGE"
    ;;
esac

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

exec "\$BROWSER_BIN" \
  --kiosk \
  --incognito \
  --noerrdialogs \
  --disable-infobars \
  --disable-session-crashed-bubble \
  --no-first-run \
  --enable-features=OverlayScrollbar \
  --start-maximized \
  "\${WAITING_PAGE_URL}"
EOF
  chmod 0755 "$USER_HOME/.local/bin/photobooth-kiosk.sh"

  cat > "$USER_HOME/.config/autostart/photobooth-kiosk.desktop" <<EOF
[Desktop Entry]
Type=Application
Name=Photobooth Kiosk
Exec=$USER_HOME/.local/bin/photobooth-kiosk.sh
Terminal=false
X-GNOME-Autostart-enabled=true
EOF

  cat > "$DESKTOP_DIR/photobooth-kiosk.desktop" <<EOF
[Desktop Entry]
Type=Application
Version=1.0
Name=Photobooth Kiosk
Comment=Restart the photobooth kiosk browser
Exec=$USER_HOME/.local/bin/photobooth-kiosk.sh
Terminal=false
Icon=web-browser
Categories=Utility;
StartupNotify=false
EOF
  chmod 0755 "$DESKTOP_DIR/photobooth-kiosk.desktop"
  chown "$KIOSK_USER:$USER_GROUP" "$DESKTOP_DIR/photobooth-kiosk.desktop"

  LABWC_BLOCK=$(mktemp)
  cat > "$LABWC_BLOCK" <<EOF
# >>> photobooth kiosk >>>
$USER_HOME/.local/bin/photobooth-kiosk.sh &
# <<< 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/.local" "$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 "Stored kiosk URL metadata: $KIOSK_URL_PATH"
  echo "Configured browser package: $BROWSER_PACKAGE"
  echo "Desktop launcher: $DESKTOP_DIR/photobooth-kiosk.desktop"
  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 "$@"
        ;;
      set-url)
        shift 2
        set_kiosk_url "$@"
        ;;
      *)
        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
