#!/usr/bin/env bash
# OneThought — обычные обои на Mac, которые меняются сами.
#
# Берёт список мыслей с сайта, выбирает ту, что давно не показывал, скачивает
# картинку под разрешение экрана и ставит её обоями. Ставит себя в launchd:
# при входе в систему и раз в час. Без установки программ и без прав админа.
#
#   curl -fsSL https://onethought.immiijo.com/mac/onethought-wallpaper.sh | bash
#   ... | bash -s -- --theme finance --minutes 30 --lang en
#   ... | bash -s -- --once        # только сменить обои
#   ... | bash -s -- --uninstall   # убрать из автозапуска
#
# Только встроенное в macOS: bash 3.2, curl, osascript (JavaScript), launchctl.
set -euo pipefail

SITE="https://onethought.immiijo.com"
DIR="$HOME/Library/Application Support/OneThought"
LABEL="com.onethought.wallpaper"
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"

THEME="all"
MINUTES=60
LANG_="ru"
ONCE=0
UNINSTALL=0

while [ $# -gt 0 ]; do
  case "$1" in
    --theme) THEME="$2"; shift 2 ;;
    --minutes) MINUTES="$2"; shift 2 ;;
    --lang) LANG_="$2"; shift 2 ;;
    --once) ONCE=1; shift ;;
    --uninstall) UNINSTALL=1; shift ;;
    *) echo "Неизвестный параметр: $1" >&2; exit 2 ;;
  esac
done

case "$THEME" in all|finance|health|focus|discipline) ;; *) echo "--theme: all, finance, health, focus или discipline" >&2; exit 2 ;; esac
case "$LANG_" in ru|en) ;; *) echo "--lang: ru или en" >&2; exit 2 ;; esac
case "$MINUTES" in ''|*[!0-9]*) echo "--minutes: целое число" >&2; exit 2 ;; esac
[ "$MINUTES" -ge 10 ] || MINUTES=10

if [ "$UNINSTALL" = 1 ]; then
  launchctl bootout "gui/$(id -u)" "$PLIST" 2>/dev/null || true
  rm -f "$PLIST"
  echo "Убрано из автозапуска. Обои остались те, что стоят сейчас."
  echo "Картинки и настройки: $DIR (можно удалить)."
  exit 0
fi

mkdir -p "$DIR"
JSON="$DIR/thoughts.json"

# Свежий список мыслей; без сети — работаем на сохранённом.
if curl -fsS --max-time 20 "$SITE/api/thoughts.json" -o "$JSON.tmp" 2>/dev/null; then
  mv "$JSON.tmp" "$JSON"
else
  rm -f "$JSON.tmp"
fi

latest_wall() { ls -t "$DIR"/wall-*.png 2>/dev/null | head -n 1 || true; }

PICK=""
if [ -f "$JSON" ]; then
  # Выбор мысли и размера картинки — на JavaScript внутри osascript:
  # он умеет и JSON, и размер экрана, а ставить ничего не нужно.
  PICK=$(osascript -l JavaScript - "$JSON" "$DIR/seen.json" "$THEME" "$LANG_" <<'JXA'
ObjC.import('Foundation');
ObjC.import('AppKit');

function readText(p) {
  var s = $.NSString.stringWithContentsOfFileEncodingError(p, $.NSUTF8StringEncoding, null);
  return s.isNil() ? null : s.js;
}

function writeText(p, t) {
  $(t).writeToFileAtomicallyEncodingError(p, true, $.NSUTF8StringEncoding, null);
}

function run(argv) {
  var data = JSON.parse(readText(argv[0]));
  var theme = argv[2], lang = argv[3];
  var pool = data.thoughts.filter(function (t) { return theme === 'all' || t.category === theme; });
  if (lang === 'en') pool = pool.filter(function (t) { return t.title_en; });
  if (!pool.length) return '';

  var seen = [];
  try { seen = JSON.parse(readText(argv[1]) || '[]'); } catch (e) { seen = []; }
  var fresh = pool.filter(function (t) { return seen.indexOf(t.slug) < 0; });
  if (!fresh.length) { fresh = pool; seen = []; }
  var pick = fresh[Math.floor(Math.random() * fresh.length)];
  seen.push(pick.slug);
  writeText(argv[1], JSON.stringify(seen.slice(-50)));

  // ближайший больший из готовых размеров, портретный экран — телефонный
  var screen = $.NSScreen.mainScreen;
  var k = screen.backingScaleFactor;
  var w = screen.frame.size.width * k, h = screen.frame.size.height * k;
  var size = h > w ? '1170x2532' : w <= 1920 ? '1920x1080' : '2560x1440';

  return pick.slug + ' ' + size + ' ' + (lang === 'en' ? pick.title_en : pick.title);
}
JXA
  ) || PICK=""
fi

WALL=""
if [ -n "$PICK" ]; then
  read -r SLUG SIZE TITLE <<EOF
$PICK
EOF
  # macOS кэширует обои по пути файла — каждая картинка под новым именем
  NEXT="$DIR/wall-$(date +%s).png"
  if curl -fsS --max-time 60 "$SITE/img/$SLUG/$LANG_/$SIZE.png" -o "$NEXT" 2>/dev/null; then
    WALL="$NEXT"
    echo "Обои: $TITLE"
  else
    rm -f "$NEXT"
  fi
fi

if [ -z "$WALL" ]; then
  WALL=$(latest_wall)
  [ -n "$WALL" ] || { echo "Нет связи с сайтом и нет сохранённых картинок." >&2; exit 1; }
  echo "Нет связи с сайтом — оставляю прошлую картинку."
fi

# Ставим на все экраны через NSWorkspace: не нужно разрешение на управление System Events.
osascript -l JavaScript - "$WALL" >/dev/null <<'JXA'
ObjC.import('AppKit');
function run(argv) {
  var url = $.NSURL.fileURLWithPath(argv[0]);
  var ws = $.NSWorkspace.sharedWorkspace;
  var screens = $.NSScreen.screens;
  for (var i = 0; i < screens.count; i++) {
    ws.setDesktopImageURLForScreenOptionsError(url, screens.objectAtIndex(i), $({}), null);
  }
  return 'ok';
}
JXA

# Старые картинки не копим: оставляем три последних.
ls -t "$DIR"/wall-*.png 2>/dev/null | tail -n +4 | while IFS= read -r old; do rm -f "$old"; done

[ "$ONCE" = 1 ] && exit 0

# Автозапуск: копия скрипта рядом с данными + агент launchd.
SELF="$DIR/onethought-wallpaper.sh"
curl -fsS --max-time 20 "$SITE/mac/onethought-wallpaper.sh" -o "$SELF.tmp" && mv "$SELF.tmp" "$SELF"
chmod +x "$SELF"

mkdir -p "$HOME/Library/LaunchAgents"
cat > "$PLIST" <<PLISTXML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>$LABEL</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/bash</string>
    <string>$SELF</string>
    <string>--once</string>
    <string>--theme</string><string>$THEME</string>
    <string>--lang</string><string>$LANG_</string>
  </array>
  <key>StartInterval</key><integer>$((MINUTES * 60))</integer>
  <key>RunAtLoad</key><true/>
  <key>StandardErrorPath</key><string>$DIR/error.log</string>
</dict>
</plist>
PLISTXML

launchctl bootout "gui/$(id -u)" "$PLIST" 2>/dev/null || true
launchctl bootstrap "gui/$(id -u)" "$PLIST"

echo "Готово. Мысль будет меняться каждые $MINUTES минут и при входе в систему."
echo "Убрать: curl -fsSL $SITE/mac/onethought-wallpaper.sh | bash -s -- --uninstall"
