#!/usr/bin/env bash
#
# Smart Home Touch-Panel ISO Builder
# Target: builds a Debian 12 (Bookworm) live ISO on a Debian/Ubuntu build machine
#
# Drives `lb config && lb build` over hosts/touch-panel/live-build/ to produce the
# Sway touch-panel image described in docs/project-plan.md Phase 16:
#   - greetd autologin straight into a kiosk Sway session (no greeter UI)
#   - touchpanel-agent (Python, systemd) — HA MQTT-discovery entities + swaymsg control
#   - workspaces 1:spotify (full Spotify GUI, Flathub) / 2:home (Chromium kiosk
#     pointed at Home Assistant) / 3:web (general Firefox browsing)
#   - an always-visible eww touch dock for on-screen app switching
#   - a toggleable on-screen keyboard (wvkbd)
#
# Reuses hosts/thin-client's own live-build toolchain and directory-split convention,
# NOT its live-build tree — this is a different device (touched directly, not
# remote-controlled from the couch) with a different app set, so it gets its own
# smaller config/, agent/, and live-build/, same relationship as
# hosts/audio-endpoint's amd64 build to the thin client's.
#
# This script is also the single point that keeps configs/ (the human-edited source of
# truth, reviewed in git) in sync with live-build/config/includes.chroot/ (the
# generated tree that actually gets baked into the image). Never hand-edit anything
# under includes.chroot — it is wiped and regenerated on every run.
#
# Run as: sudo -E tools/build-touch-panel-iso.sh [hostname]
#
# Configuration comes from CoreSystemConfig.json — see tools/README.md.

set -euo pipefail

# ---------------------------------------------------------------------------
# CONFIGURATION — comes from CoreSystemConfig.json, NOT from this file.
#
# There is nothing to edit here any more. Every value below is read from the one
# config at the repo root, so an address or token can only be wrong in a single
# place. Change it there and rebuild; see tools/README.md.
#
#   sudo -E tools/build-touch-panel-iso.sh                 # the only touch-panel in the config
#   sudo -E tools/build-touch-panel-iso.sh <hostname>      # a specific one, if several are defined
#
# The build refuses to start if the config is invalid (validate-config.py runs first),
# so a typo costs seconds rather than a 40-minute build and a reboot.
# ---------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/coreconfig.sh
source "${SCRIPT_DIR}/lib/coreconfig.sh"

core_select_kiosk "touch-panel" "${1:-}"

# Mapped onto this script's existing variable names, so everything below is unchanged
# from when these were hand-edited constants.
DEBIAN_RELEASE="$CORE_DEBIAN_RELEASE"
KIOSK_USERNAME="$CORE_KIOSK_USERNAME"
IMAGE_HOSTNAME="$CORE_KIOSK_HOSTNAME"
KEYBOARD_LAYOUT="$CORE_KEYBOARD_LAYOUT"
ENABLE_INSTALLER="$CORE_KIOSK_ENABLE_INSTALLER"
MQTT_BROKER_HOST="$CORE_MQTT_BROKER_HOST"
MQTT_BROKER_PORT="$CORE_MQTT_BROKER_PORT"
MQTT_USERNAME="$CORE_MQTT_USERNAME"
MQTT_PASSWORD="$CORE_MQTT_PASSWORD"
SSH_AUTHORIZED_KEY="$CORE_SSH_AUTHORIZED_KEY"
ENABLE_VOICE_SATELLITE="$CORE_KIOSK_VOICE_SATELLITE"
VOICE_SATELLITE_NAME="$CORE_KIOSK_FRIENDLY_NAME"
VOICE_WAKE_WORD="$CORE_KIOSK_WAKE_WORD"
TOUCHPANEL_NAME="$CORE_KIOSK_FRIENDLY_NAME"
# The HA area this device physically sits in, from the kiosk's `room` in
# CoreSystemConfig.json. The agent publishes it as suggested_area so HA files
# the device in the right room by itself — see docs/rooms-and-endpoints.md.
TOUCHPANEL_ROOM="${CORE_KIOSK_ROOM:-}"
# Discord as a fourth app on this panel (kiosks[].enable_discord). Per-panel, not
# per-image-type: the Loggia panel wants it so a voice call survives stepping outside
# for a cigarette; a kitchen panel does not want a chat client at all.
ENABLE_DISCORD="${CORE_KIOSK_ENABLE_DISCORD:-false}"
HA_URL="$CORE_HA_URL"

# ---------------------------------------------------------------------------
# Paths — this script now lives in tools/, so the host directory it drives is
# addressed from the repo root rather than relative to the script.
# ---------------------------------------------------------------------------
TOUCH_PANEL_DIR="${CORE_REPO_ROOT}/hosts/touch-panel"
CONFIGS_DIR="${TOUCH_PANEL_DIR}/configs"
AGENT_DIR="${TOUCH_PANEL_DIR}/agent"
LIVE_BUILD_DIR="${TOUCH_PANEL_DIR}/live-build"
INCLUDES="${LIVE_BUILD_DIR}/config/includes.chroot"
PACKAGE_LIST="${LIVE_BUILD_DIR}/config/package-lists/touch-panel.list.chroot"

# ---------------------------------------------------------------------------
# Sanity checks
# ---------------------------------------------------------------------------
if [[ $EUID -ne 0 ]]; then
  echo "Warning: not running as root. 'lb build' needs root to bootstrap and chroot,"
  echo "  and will fail partway through. Re-run with: sudo $0"
  echo "  Continuing anyway so you can at least regenerate includes.chroot..."
fi

if ! grep -qi "debian\|ubuntu" /etc/os-release; then
  echo "Warning: live-build targets a Debian/Ubuntu build host. Proceeding anyway..."
fi

if ! command -v lb &> /dev/null; then
  if [[ $EUID -eq 0 ]]; then
    echo "--- Installing live-build ---"
    apt-get update
    apt-get install -y live-build
  else
    echo "live-build is not installed and this script is not running as root." >&2
    echo "  Install it first: sudo apt-get install live-build" >&2
    exit 1
  fi
else
  echo "--- live-build already installed, skipping ---"
fi

if [[ ! -f "$PACKAGE_LIST" ]]; then
  echo "Missing package list: $PACKAGE_LIST" >&2
  exit 1
fi



echo
echo "=== Smart Home Touch-Panel ISO Builder ==="
echo "Debian release   : $DEBIAN_RELEASE"
echo "Kiosk user       : $KIOSK_USERNAME"
echo "Image hostname   : $IMAGE_HOSTNAME"
echo "MQTT broker      : ${MQTT_BROKER_HOST}:${MQTT_BROKER_PORT}"
echo "Home Assistant   : $HA_URL"
echo "Keyboard layout  : $KEYBOARD_LAYOUT"
echo

# ---------------------------------------------------------------------------
# 1. Regenerate includes.chroot from configs/ and agent/
# ---------------------------------------------------------------------------
echo "--- Regenerating $INCLUDES ---"
rm -rf "$INCLUDES"
mkdir -p \
  "$INCLUDES/etc/greetd" \
  "$INCLUDES/etc/touchpanel-agent" \
  "$INCLUDES/etc/firefox/policies" \
  "$INCLUDES/etc/touchpanel-firefox" \
  "$INCLUDES/etc/udev/rules.d" \
  "$INCLUDES/usr/local/bin" \
  "$INCLUDES/opt/touchpanel-agent" \
  "$INCLUDES/home/${KIOSK_USERNAME}/.config/sway" \
  "$INCLUDES/home/${KIOSK_USERNAME}/.config/eww" \
  "$INCLUDES/home/${KIOSK_USERNAME}/.ssh"

# @KIOSK_USERNAME@ and @KEYBOARD_LAYOUT@ are the only templated tokens in the configs.
# Everything else the hooks need is read at build time from
# /etc/touchpanel-agent/config.env (written below), which live-build copies in
# (chroot_local-includes) before it runs the hooks (chroot_local-hooks).
subst() {
  sed -e "s/@KIOSK_USERNAME@/${KIOSK_USERNAME}/g" \
      -e "s/@KEYBOARD_LAYOUT@/${KEYBOARD_LAYOUT}/g" "$1" > "$2"
}

subst "${CONFIGS_DIR}/greetd/config.toml" "$INCLUDES/etc/greetd/config.toml"
subst "${CONFIGS_DIR}/sway/config"        "$INCLUDES/home/${KIOSK_USERNAME}/.config/sway/config"
subst "${AGENT_DIR}/touchpanel-agent.service" "$INCLUDES/opt/touchpanel-agent/touchpanel-agent.service"

install -m 0755 "${CONFIGS_DIR}/greetd/kiosk-session"       "$INCLUDES/usr/local/bin/kiosk-session"
install -m 0755 "${CONFIGS_DIR}/sway/ha-kiosk"               "$INCLUDES/usr/local/bin/ha-kiosk"
install -m 0755 "${CONFIGS_DIR}/spotify/spotify-launch"      "$INCLUDES/usr/local/bin/spotify-launch"
install -m 0755 "${CONFIGS_DIR}/discord/discord-launch"      "$INCLUDES/usr/local/bin/discord-launch"
install -m 0755 "${CONFIGS_DIR}/keyboard/toggle-keyboard"    "$INCLUDES/usr/local/bin/toggle-keyboard"

# Touchscreen misclassification override (inert 0000:0000 template until the real
# hardware's vendor/product ID is filled in — see that file's own setup steps).
install -m 0644 "${CONFIGS_DIR}/udev/99-touchscreen-override.rules" \
  "$INCLUDES/etc/udev/rules.d/99-touchscreen-override.rules"

# Console (VT/TTY) keymap — separate from Sway's own xkb_layout, since greetd briefly
# owns the console before Sway starts.
mkdir -p "$INCLUDES/etc/default"
cat > "$INCLUDES/etc/default/keyboard" <<EOF
XKBMODEL="pc105"
XKBLAYOUT="${KEYBOARD_LAYOUT}"
XKBVARIANT=""
XKBOPTIONS=""

BACKSPACE="guess"
EOF

# Touch dock (eww) — session-scoped files under the kiosk user's own config.
# The dock's one templated token is the Discord button: a button for an app this image
# did not install would switch to an empty workspace, which reads as a broken panel
# rather than a disabled feature. The replacement is a fixed string chosen here, never
# anything derived from config values — same rule as eww.yuck's own header.
if [[ "$ENABLE_DISCORD" == "true" ]]; then
  DISCORD_DOCK_BTN='    (dock-btn :ws "4:discord" :icon "💬" :label "Discord")'
else
  DISCORD_DOCK_BTN=""
fi
awk -v btn="$DISCORD_DOCK_BTN" '
  /^@DISCORD_DOCK_BTN@/ {
    if (btn != "") print btn
    sub(/^@DISCORD_DOCK_BTN@/, "")
  }
  { print }
' "${CONFIGS_DIR}/eww/eww.yuck" > "$INCLUDES/home/${KIOSK_USERNAME}/.config/eww/eww.yuck"
chmod 0644 "$INCLUDES/home/${KIOSK_USERNAME}/.config/eww/eww.yuck"
install -m 0644 "${CONFIGS_DIR}/eww/eww.scss" "$INCLUDES/home/${KIOSK_USERNAME}/.config/eww/eww.scss"

# Firefox: the general-browsing window launcher, plus the shared chrome/prefs template
# it copies into its own profile at launch. policies.json is global and goes straight
# into includes.chroot.
install -m 0755 "${CONFIGS_DIR}/firefox/web-browser"    "$INCLUDES/usr/local/bin/web-browser"
install -m 0644 "${CONFIGS_DIR}/firefox/policies.json"  "$INCLUDES/etc/firefox/policies/policies.json"
install -m 0644 "${CONFIGS_DIR}/firefox/userChrome.css" "$INCLUDES/etc/touchpanel-firefox/userChrome.css"
install -m 0644 "${CONFIGS_DIR}/firefox/user.js"        "$INCLUDES/etc/touchpanel-firefox/user.js"

cp -r "${AGENT_DIR}/touchpanel_agent" "$INCLUDES/opt/touchpanel-agent/"
install -m 0644 "${AGENT_DIR}/requirements.txt" "$INCLUDES/opt/touchpanel-agent/requirements.txt"
find "$INCLUDES/opt/touchpanel-agent" -name '__pycache__' -type d -prune -exec rm -rf {} +

if [[ -n "$SSH_AUTHORIZED_KEY" ]]; then
  echo "$SSH_AUTHORIZED_KEY" > "$INCLUDES/home/${KIOSK_USERNAME}/.ssh/authorized_keys"
  chmod 600 "$INCLUDES/home/${KIOSK_USERNAME}/.ssh/authorized_keys"
  echo "  Baked an SSH authorized_keys entry for ${KIOSK_USERNAME}."
else
  echo "  No SSH_AUTHORIZED_KEY set — SSH admin access will not be possible on this image."
fi

# ---------------------------------------------------------------------------
# 2. Runtime config, read by touchpanel-agent, the sway session wrapper, and hooks
# ---------------------------------------------------------------------------
echo "--- Writing /etc/touchpanel-agent/config.env into includes.chroot ---"
cat > "$INCLUDES/etc/touchpanel-agent/config.env" <<EOF
# Generated by tools/build-touch-panel-iso.sh — do not hand-edit
# here; change CoreSystemConfig.json at the repo root and rebuild.
KIOSK_USERNAME=${KIOSK_USERNAME}
TOUCHPANEL_NAME=${TOUCHPANEL_NAME}
TOUCHPANEL_ROOM=${TOUCHPANEL_ROOM}

MQTT_BROKER_HOST=${MQTT_BROKER_HOST}
MQTT_BROKER_PORT=${MQTT_BROKER_PORT}
MQTT_USERNAME=${MQTT_USERNAME}
MQTT_PASSWORD=${MQTT_PASSWORD}

HA_URL=${HA_URL}

# Read by 0350-flatpak-discord.hook.chroot at build time, by the sway config's
# autostart line at session start, and by touchpanel-agent's build_apps().
ENABLE_DISCORD=${ENABLE_DISCORD}
EOF
chmod 0644 "$INCLUDES/etc/touchpanel-agent/config.env"

# ---------------------------------------------------------------------------
# 3. lb config
# ---------------------------------------------------------------------------
cd "$LIVE_BUILD_DIR"

chmod +x config/hooks/normal/*.hook.chroot

if [[ -e .build ]]; then
  echo "--- Previous build found, running 'lb clean' (package cache is kept) ---"
  lb clean
fi

INSTALLER_MODE="none"
if [[ "$ENABLE_INSTALLER" == "true" ]]; then
  INSTALLER_MODE="live"
fi

echo "--- Running lb config ---"
lb config \
  --distribution "$DEBIAN_RELEASE" \
  --architectures amd64 \
  --linux-flavours amd64 \
  --archive-areas "main contrib non-free-firmware" \
  --binary-images iso-hybrid \
  --debian-installer "$INSTALLER_MODE" \
  --iso-application "SmartestHome Touch Panel" \
  --iso-publisher "SmartestHome" \
  --iso-volume "smarthome-touch-panel" \
  --memtest none \
  --bootappend-live "boot=live components quiet splash noautologin username=${KIOSK_USERNAME} hostname=${IMAGE_HOSTNAME}"

# ---------------------------------------------------------------------------
# 4. lb build
# ---------------------------------------------------------------------------
echo "--- Running lb build (this takes a while and needs network) ---"
lb build

ISO_PATH="$(find "$LIVE_BUILD_DIR" -maxdepth 1 -name '*.iso' -print -quit)"
ISO_PATH="${ISO_PATH:-${LIVE_BUILD_DIR}/live-image-amd64.hybrid.iso}"
# Published under this kiosk's own hostname — live-build reuses one filename per host
# tree, so two of the same kiosk type would otherwise overwrite each other.
ISO_PATH="$(core_publish_image "$ISO_PATH" "touch-panel" "$IMAGE_HOSTNAME")"

echo
echo "=== Done ==="
echo "ISO written to:"
echo "  ${ISO_PATH}"
echo
echo "What's in it:"
echo "  greetd            : autologin as '${KIOSK_USERNAME}' straight into Sway on vt1"
if [[ "$ENABLE_DISCORD" == "true" ]]; then
  echo "  Sway              : workspaces 1:spotify / 2:home / 3:web / 4:discord, always-on touch dock"
else
  echo "  Sway              : workspaces 1:spotify / 2:home / 3:web, always-on touch dock"
fi
echo "  touchpanel-agent  : system service, MQTT ${MQTT_BROKER_HOST}:${MQTT_BROKER_PORT}"
echo "  Spotify           : full GUI client (Flathub com.spotify.Client), workspace 1"
echo "  Home Assistant    : Chromium kiosk, ${HA_URL}, workspace 2, auto-restart-on-crash"
echo "  Web browser       : Firefox, minimal chrome, uBlock Origin + SponsorBlock, workspace 3"
if [[ "$ENABLE_DISCORD" == "true" ]]; then
  echo "  Discord           : full GUI client (Flathub com.discordapp.Discord), workspace 4,"
  echo "                      started at session boot and left running — the point is"
  echo "                      stepping out mid-call, not reading messages"
  echo "  Touch dock        : bottom bar (eww) — Spotify / Home / Web / Discord / Keyboard"
else
  echo "  Touch dock        : bottom bar (eww) — Spotify / Home / Web / Keyboard buttons"
fi
echo "  On-screen keyboard: wvkbd, toggled from the dock's Keyboard button"
echo "  Touchscreen input : native wl_touch preferred; degrades to a usable"
echo "                      single-touch/click-drag pointer if the hardware reports"
echo "                      as an emulated-mouse HID device instead — see README.md"
echo "                      '99-touchscreen-override.rules' to fix it properly once"
echo "                      the real hardware's USB vendor/product ID is known"
echo "  Keyboard layout   : ${KEYBOARD_LAYOUT} (console + Sway)"
echo "  Maintenance shell : Super+Shift+Ctrl+M opens a floating terminal locally"
echo "  Remote admin      : SSH only — no wayvnc on this image, see README"
echo
echo "Next steps:"
echo "  1. Write the ISO to a USB stick:"
echo "       sudo dd if=${ISO_PATH} of=/dev/sdX bs=4M status=progress oflag=sync"
echo "     (double-check /dev/sdX with 'lsblk' first — dd will happily eat the wrong disk)"
echo "  2. Boot the target touchscreen machine from it. No touch-panel hardware has been"
echo "     chosen yet (see the README) — check which way libinput classified the"
echo "     touchscreen:  libinput list-devices | grep -A2 Capabilities"
echo "     If it says 'touch', full multi-touch works out of the box. If it says"
echo "     'pointer' instead, taps still work (single-touch click) via the fallback"
echo "     input config, but fill in configs/udev/99-touchscreen-override.rules with"
echo "     the device's real USB vendor/product ID and rebuild for the real fix —"
echo "     see that file's own setup steps and the README."
echo "  3. Confirm greetd autologin lands in Sway: dark background, the touch dock at"
echo "     the bottom, and the Home Assistant kiosk window on workspace 2:home."
echo "  4. Tap through the dock: Spotify (log in on first launch — Premium required),"
echo "     Home, Web."
echo "  5. Confirm touchpanel-agent connected and registered:"
echo "       systemctl status touchpanel-agent"
echo "     In Home Assistant, a '${TOUCHPANEL_NAME}' device should appear under the MQTT"
echo "     integration with: Show Spotify / Show Home / Show web browser (buttons),"
echo "     Screen (select), Volume (number), Playback state (sensor), and"
echo "     play/pause/next/prev/stop buttons."
echo "  6. Start something in Spotify and confirm Playback state follows it (playerctl"
echo "     -> touchpanel-agent's MPRIS bridge — needs Spotify's own MPRIS bus name to"
echo "     actually be 'spotify', unverified against the real Flatpak build)."
echo "  7. Tap the dock's Keyboard button over a text field (Spotify search, the browser"
echo "     address bar) and confirm wvkbd shows/hides. There is no auto-show — see README."
echo
echo "Then pull the power on the container host and re-check: the panel must still boot"
echo "and show Spotify/the browser (Home will show a connection error, which is"
echo "expected) with the container host powered off — same reactive-path philosophy as"
echo "hosts/thin-client's Phase 11.10."
echo
echo "Rebuilding later: edit hosts/touch-panel/configs/* or agent/*, then re-run this"
echo "script — includes.chroot is regenerated from them every time."
