#!/bin/sh
# rikkiti-clip-store — Rikkiti clipboard store mutations.
#
#   rikkiti-clip-store text|image     store stdin as a new entry (dedup, capped)
#   rikkiti-clip-store delete <id>    remove a single entry + its file
#
# Storing reads raw content from stdin (binary-safe via a temp file). Identical
# content dedups (same sha → moves to top). The store is capped at `max_entries`
# from ~/.config/rikkiti/clipboard.conf (default 200); oldest are evicted. Private
# mode (PAUSED file) and password-manager copies are dropped. Invoked by
# rikkiti-clipd's `wl-paste --watch` watchers + the panel applet (delete). POSIX sh.
set -eu

KIND="${1:-text}"
DIR="${XDG_DATA_HOME:-$HOME/.local/share}/rikkiti/clipboard"
ITEMS="$DIR/items"
INDEX="$DIR/index"
PAUSED="$DIR/PAUSED"
LOCK="$DIR/.lock"
CONF="${XDG_CONFIG_HOME:-$HOME/.config}/rikkiti/clipboard.conf"

conf_val() { grep -E "^[[:space:]]*$1[[:space:]]*=" "$CONF" 2>/dev/null | tail -1 | sed 's/^[^=]*=//; s/#.*//; s/[[:space:]]//g'; }

mkdir -p "$ITEMS"

lock()   { i=0; while ! mkdir "$LOCK" 2>/dev/null; do i=$((i + 1)); [ "$i" -gt 50 ] && break; sleep 0.05; done; }
unlock() { rmdir "$LOCK" 2>/dev/null || true; }

# ---- delete a single entry -------------------------------------------------
if [ "$KIND" = "delete" ]; then
	ID="${2:-}"
	[ -n "$ID" ] || exit 0
	lock
	rm -f "$ITEMS/$ID"
	if [ -f "$INDEX" ]; then
		awk -F'\t' -v id="$ID" '$1 != id' "$INDEX" >"$INDEX.new" 2>/dev/null || true
		mv "$INDEX.new" "$INDEX" 2>/dev/null || true
	fi
	unlock
	exit 0
fi

# ---- store from stdin ------------------------------------------------------
# Disabled in Settings (persistent off) — discard.
case "$(conf_val enabled)" in false | 0 | no) cat >/dev/null; exit 0 ;; esac
# Private mode (PAUSED file) — discard (drain stdin so the writer's pipe doesn't break).
if [ -e "$PAUSED" ]; then cat >/dev/null; exit 0; fi

# Skip password-manager copies — KeePassXC / KDE / GTK mark them with the
# x-kde-passwordManagerHint MIME type so secrets never hit the history file.
if [ "$KIND" = "text" ] && wl-paste --list-types 2>/dev/null | grep -qi 'x-kde-passwordManagerHint'; then
	cat >/dev/null
	exit 0
fi

# Max history entries (Settings ▸ Clipboard writes clipboard.conf).
CAP=$(conf_val max_entries || true)
{ [ -n "$CAP" ] && [ "$CAP" -gt 0 ] 2>/dev/null; } || CAP=200

# Capture stdin to a temp file (binary-safe).
TMP="$(mktemp "$DIR/.in.XXXXXX")"
trap 'rm -f "$TMP"' EXIT INT TERM
cat >"$TMP"

BYTES=$(wc -c <"$TMP" | tr -d ' ')
[ "$BYTES" -gt 0 ] || exit 0

ID=$(sha256sum "$TMP" | cut -c1-16)

if [ "$KIND" = "image" ]; then
	PREVIEW="image"
else
	PREVIEW=$(tr '\t\r' '  ' <"$TMP" | sed -n '/[^[:space:]]/{p;q}' | cut -c1-120)
	[ -n "$PREVIEW" ] || PREVIEW="(whitespace)"
fi

cp "$TMP" "$ITEMS/$ID"

lock
NEW="$DIR/.index.new"
{
	printf '%s\t%s\t%s\t%s\n' "$ID" "$KIND" "$BYTES" "$PREVIEW"
	if [ -f "$INDEX" ]; then
		while IFS= read -r line || [ -n "$line" ]; do
			case "$line" in
				"$ID	"*) ;; # same id (tab after id) → drop the old one (dedup)
				*) printf '%s\n' "$line" ;;
			esac
		done <"$INDEX"
	fi
} >"$NEW"

# Cap: keep newest CAP lines, evict unreferenced items.
if [ "$(wc -l <"$NEW")" -gt "$CAP" ]; then
	head -n "$CAP" "$NEW" >"$NEW.cap"
	cut -f1 "$NEW.cap" >"$DIR/.keep"
	for f in "$ITEMS"/*; do
		[ -e "$f" ] || continue
		bn=${f##*/}
		grep -qx "$bn" "$DIR/.keep" || rm -f "$f"
	done
	mv "$NEW.cap" "$NEW"
	rm -f "$DIR/.keep"
fi

mv "$NEW" "$INDEX"
unlock
