#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<'EOF'
Usage:
  tools/watch_prompt_image_folder.sh --folder DIR --target TMUX_TARGET [options]

Watch a folder for prompt/image pairs and notify a selected Byobu/tmux Codex
pane using tmux send-keys. Prompt and image files are paired by basename:
  atlas_case_001.txt + atlas_case_001.png
  atlas_case_002.prompt + atlas_case_002.jpg

Required:
  --folder DIR          Folder to watch.
  --target TARGET       tmux target pane, for example session:1.0.

Options:
  --notes FILE          Notes/output file to mention in the Codex message.
                        Default: DIR/prompt-learning.md
  --state FILE          Seen-state file. Default: DIR/.sxcp_watch_seen
  --once                Scan once and exit.
  --dry-run             Print tmux send-keys commands instead of sending them.
  --poll-interval SEC   Poll/fallback interval in seconds. Default: 2
  --stable-delay SEC    Seconds to wait before accepting a new image. Default: 1
  --prompt-exts CSV     Prompt extensions. Default: txt,prompt
  --image-exts CSV      Image extensions. Default: png,jpg,jpeg,webp
  -h, --help            Show this help.

Inside Byobu/tmux, get the current target with:
  tmux display-message -p '#S:#I.#P'
EOF
}

folder=""
target=""
notes=""
state=""
once=0
dry_run=0
poll_interval=2
stable_delay=1
prompt_exts_csv="txt,prompt"
image_exts_csv="png,jpg,jpeg,webp"

while [[ $# -gt 0 ]]; do
  case "$1" in
    --folder)
      folder="${2:-}"
      shift 2
      ;;
    --target)
      target="${2:-}"
      shift 2
      ;;
    --notes)
      notes="${2:-}"
      shift 2
      ;;
    --state)
      state="${2:-}"
      shift 2
      ;;
    --once)
      once=1
      shift
      ;;
    --dry-run)
      dry_run=1
      shift
      ;;
    --poll-interval)
      poll_interval="${2:-}"
      shift 2
      ;;
    --stable-delay)
      stable_delay="${2:-}"
      shift 2
      ;;
    --prompt-exts)
      prompt_exts_csv="${2:-}"
      shift 2
      ;;
    --image-exts)
      image_exts_csv="${2:-}"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "unknown argument: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

if [[ -z "$folder" || -z "$target" ]]; then
  echo "--folder and --target are required" >&2
  usage >&2
  exit 2
fi

if [[ ! -d "$folder" ]]; then
  echo "folder does not exist: $folder" >&2
  exit 2
fi

folder="$(cd "$folder" && pwd -P)"
if [[ -z "$notes" ]]; then
  notes="$folder/prompt-learning.md"
fi
if [[ -z "$state" ]]; then
  state="$folder/.sxcp_watch_seen"
fi
if [[ "$notes" != /* ]]; then
  notes="$PWD/$notes"
fi
if [[ "$state" != /* ]]; then
  state="$PWD/$state"
fi

mkdir -p "$(dirname "$state")"
touch "$state"

IFS=',' read -r -a prompt_exts <<< "$prompt_exts_csv"
IFS=',' read -r -a image_exts <<< "$image_exts_csv"

shell_quote() {
  printf '%q' "$1"
}

state_key() {
  local prompt_path="$1"
  local image_path="$2"
  printf '%s | %s\n' "$prompt_path" "$image_path"
}

is_seen() {
  local key="$1"
  grep -Fxq -- "$key" "$state"
}

mark_seen() {
  local key="$1"
  printf '%s\n' "$key" >> "$state"
}

file_size() {
  wc -c < "$1" | tr -d '[:space:]'
}

wait_for_stable_image() {
  local image_path="$1"
  if [[ "$dry_run" -eq 1 || "$stable_delay" == "0" ]]; then
    return 0
  fi
  local before
  local after
  before="$(file_size "$image_path")"
  sleep "$stable_delay"
  after="$(file_size "$image_path")"
  [[ "$before" == "$after" ]]
}

find_image_for_prompt() {
  local prompt_path="$1"
  local filename
  local stem
  local ext
  local candidate
  filename="$(basename "$prompt_path")"
  stem="${filename%.*}"
  for ext in "${image_exts[@]}"; do
    candidate="$folder/$stem.$ext"
    if [[ -f "$candidate" ]]; then
      printf '%s\n' "$candidate"
      return 0
    fi
    candidate="$folder/$stem.${ext^^}"
    if [[ -f "$candidate" ]]; then
      printf '%s\n' "$candidate"
      return 0
    fi
  done
  return 1
}

notify_codex() {
  local prompt_path="$1"
  local image_path="$2"
  local message
  message="New atlas sample ready: prompt=$prompt_path image=$image_path. Analyze it and append prompt-learning notes to $notes."
  if [[ "$dry_run" -eq 1 ]]; then
    printf 'tmux send-keys -t %s %s Enter\n' "$(shell_quote "$target")" "$(shell_quote "$message")"
    return 0
  fi
  tmux send-keys -t "$target" "$message" Enter
}

scan_once() {
  local notified=0
  local ext
  local prompt_path
  local image_path
  local key
  for ext in "${prompt_exts[@]}"; do
    while IFS= read -r -d '' prompt_path; do
      if ! image_path="$(find_image_for_prompt "$prompt_path")"; then
        continue
      fi
      key="$(state_key "$prompt_path" "$image_path")"
      if is_seen "$key"; then
        continue
      fi
      if ! wait_for_stable_image "$image_path"; then
        continue
      fi
      notify_codex "$prompt_path" "$image_path"
      mark_seen "$key"
      notified=$((notified + 1))
    done < <(find "$folder" -maxdepth 1 -type f \( -iname "*.$ext" \) -print0)
  done
  if [[ "$notified" -eq 0 && "$once" -eq 1 ]]; then
    echo "no new prompt/image pairs in $folder"
  fi
  return 0
}

if [[ "$once" -eq 1 ]]; then
  scan_once
  exit 0
fi

scan_once
if command -v inotifywait >/dev/null 2>&1; then
  while inotifywait -qq -e close_write,create,moved_to "$folder"; do
    scan_once
  done
else
  echo "inotifywait not found; polling $folder every $poll_interval seconds" >&2
  while true; do
    sleep "$poll_interval"
    scan_once
  done
fi
