#!/bin/sh
# iris-browser — the Chrome-family launcher iris is pointed at (`iris --chrome ~/.local/bin/iris-browser`).
#
# Two jobs, both invisible to iris:
#
#   1. Pick the browser. Brave first — it is Chromium underneath, so CDP and the profile format are the
#      same — then Chromium, then Chrome. Iris only knows it asked for "a chrome".
#
#   2. Carry the user's sessions into the capture, read-only. The persistent profile is the one the
#      desktop's browser signs into (~/.config/officer/browser-profile); captures ride COPIES of its
#      cookies in a throwaway profile, so a capture can never corrupt or lock the profile that holds the
#      sessions, and the desktop browser being open never collides with a capture.
#
# Per-user isolation is $HOME: whoever runs iris gets their own profile, their own sessions, and nothing
# of anyone else's. That is the kernel's answer, not this script's.
#
# The launcher (chromiumoxide) may pass its own --user-data-dir. If it does, we seed the sessions INTO
# that directory and change nothing else — overriding it could break how the launcher finds the DevTools
# socket. If it does not, we provide an ephemeral directory ourselves and clean it up.

set -u

PROFILE="${OFFICER_BROWSER_PROFILE:-$HOME/.config/officer/browser-profile}"

BROWSER=""
for candidate in brave-browser brave chromium chromium-browser google-chrome google-chrome-stable; do
  if BROWSER="$(command -v "$candidate" 2>/dev/null)" && [ -n "$BROWSER" ]; then
    break
  fi
done
if [ -z "$BROWSER" ]; then
  echo "iris-browser: no Chrome-family browser found (looked for brave, chromium, chrome)" >&2
  echo "iris-browser: install the desktop plugin, or any of the above" >&2
  exit 127
fi

# Cookies plus the key that decrypts them. Login Data rides along so "remembered" form logins survive.
# Everything else in a profile is cache and preference noise a capture does not need.
#
# ── The -wal files are not optional ──
#
# These are SQLite databases in WAL mode, and a recent write may live ONLY in the write-ahead log: the
# browser has not checkpointed it into the .db yet. Copying `Cookies` without `Cookies-wal` therefore
# produces a profile that is missing exactly the newest sessions — sign in, capture immediately, and the
# capture is signed out, which reads as "sessions do not work" rather than as a missing file.
#
# `-shm` is deliberately NOT copied: it is shared memory for live coordination between processes, it is
# rebuilt from the WAL on open, and a stale one is worse than none.
#
# Failures are REPORTED, not swallowed. The skill tells the user to sign in again when a capture comes
# back logged out; that advice is useless if the real cause was an unreadable profile, and silence is
# what made the two indistinguishable.
seed_one() {
  [ -f "$1" ] || return 0
  cp "$1" "$2" 2>/dev/null || echo "iris-browser: could not copy $(basename "$1") — captures may be signed out" >&2
}

seed_sessions() {
  dest="$1"
  [ -d "$PROFILE/Default" ] || {
    echo "iris-browser: no profile at $PROFILE — captures will be signed out until you sign in there" >&2
    return 0
  }
  mkdir -p "$dest/Default" || return 0
  seed_one "$PROFILE/Local State" "$dest/Local State"
  for db in "Cookies" "Login Data"; do
    seed_one "$PROFILE/Default/$db" "$dest/Default/$db"
    seed_one "$PROFILE/Default/$db-wal" "$dest/Default/$db-wal"
  done
}

# Did the launcher already choose a profile directory?
#
# Both spellings. Chrome accepts `--user-data-dir=X` and `--user-data-dir X`, and matching only the first
# would send us down the ephemeral path while the launcher used its own directory — two profiles, and the
# sessions seeded into the one nobody opened.
CALLER_DIR=""
take_next=0
for arg in "$@"; do
  if [ "$take_next" -eq 1 ]; then
    CALLER_DIR="$arg"
    take_next=0
    continue
  fi
  case "$arg" in
    --user-data-dir=*) CALLER_DIR="${arg#--user-data-dir=}" ;;
    --user-data-dir) take_next=1 ;;
  esac
done

# --password-store=basic keeps cookie encryption portable between the profile and the copy: without it a
# keyring-backed browser writes cookies that the copied `Local State` key cannot decrypt, and the capture
# is signed out for a reason nothing reports. Passed on BOTH paths — chromiumoxide's own DEFAULT_ARGS
# happen to include it today, which is not something this script should depend on.
if [ -n "$CALLER_DIR" ]; then
  seed_sessions "$CALLER_DIR"
  exec "$BROWSER" "$@" --password-store=basic
fi

# CHECKED. `set -u` does not catch this: mktemp failing leaves EPHEMERAL an empty string, which becomes
# `--user-data-dir=` — and Chrome reads an empty value as "use the default profile", i.e. the user's real
# one. A capture would then run in, and write to, the browser they actually use.
if ! EPHEMERAL="$(mktemp -d "${TMPDIR:-/tmp}/iris-profile.XXXXXX")" || [ -z "$EPHEMERAL" ]; then
  echo "iris-browser: could not create a temporary profile directory — refusing to launch" >&2
  exit 1
fi
trap 'rm -rf "$EPHEMERAL"' EXIT INT TERM
seed_sessions "$EPHEMERAL"

# NOT exec'd, unlike the branch above, because the trap has to outlive the browser to remove the profile —
# and a profile holding copies of the user's cookies is not something to leave in /tmp. The cost is that
# this shell stays alive as the parent; `wait` is what makes a signal to it reach the browser rather than
# killing the wrapper and orphaning the child.
#
# Our --user-data-dir goes AFTER the launcher's args: for a repeated switch Chrome honours the last one.
"$BROWSER" "$@" --user-data-dir="$EPHEMERAL" --password-store=basic &
BROWSER_PID=$!
trap 'kill "$BROWSER_PID" 2>/dev/null; rm -rf "$EPHEMERAL"' EXIT INT TERM
wait "$BROWSER_PID"
exit $?
