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

BASE="https://scratch.duz.ie"

# Reuse a session password if exported, else prompt. (A `curl | bash` child
# can't export back, so set it yourself first to skip the prompt:
#   export DUZIE_SCRATCH_AUTH=...   then   curl -fsSL .../scratch | bash)
if [[ -n "${DUZIE_SCRATCH_AUTH:-}" ]]; then
  PASSWORD="$DUZIE_SCRATCH_AUTH"
else
  read -rsp "Password: " PASSWORD </dev/tty; echo
fi
AUTH=(-H "X-Auth-Password: $PASSWORD")

# ------------------------------------------------------------ clipboard
# Mirrors ~/.config/bash/36-clipboard: native tools when local, OSC 52 when
# SSH'd in (reaches the terminal in front of you). Reading (clip_in) has no
# OSC 52 equivalent, so it needs a native tool.
_osc52() {                       # stdin -> OSC 52 escape sequence
  local b64
  b64="$(base64 | tr -d '\n')"
  printf '\033]52;c;%s\a' "$b64"
}

clip_out() {                     # stdin -> clipboard
  if [[ -n "${SSH_TTY:-}" ]]; then
    _osc52
  elif   command -v pbcopy  >/dev/null 2>&1; then pbcopy
  elif   command -v wl-copy >/dev/null 2>&1; then wl-copy
  elif   command -v xclip   >/dev/null 2>&1; then xclip -selection clipboard -in
  elif   command -v xsel    >/dev/null 2>&1; then xsel --clipboard --input
  else
    _osc52   # headless fallback: harmless no-op where unsupported
  fi
}

clip_in() {                      # clipboard -> stdout
  if      command -v pbpaste  >/dev/null 2>&1; then pbpaste
  elif    command -v wl-paste >/dev/null 2>&1; then wl-paste
  elif    command -v xclip    >/dev/null 2>&1; then xclip -o -selection clipboard
  elif    command -v xsel     >/dev/null 2>&1; then xsel --clipboard --output
  else
    echo "No clipboard available (tried pbpaste, wl-paste, xclip, xsel)." >&2
    return 1
  fi
}

# ------------------------------------------------------------------ text
do_edit() {
  TMP="$(mktemp)"
  trap 'rm -f "$TMP"' RETURN
  if ! curl -fsSL "${AUTH[@]}" "$BASE/dev-api/scratch" -o "$TMP" 2>/dev/null; then
    echo "Failed to fetch scratchpad (wrong password or server error)." >&2
    return 1
  fi

  if command -v sha256sum >/dev/null 2>&1; then
    hashof() { sha256sum "$1" | awk '{print $1}'; }
  else
    hashof() { shasum -a 256 "$1" | awk '{print $1}'; }
  fi

  local BEFORE AFTER chosen c
  BEFORE="$(hashof "$TMP")"

  chosen=""
  if [[ -n "${EDITOR:-}" ]] && command -v "${EDITOR}" >/dev/null 2>&1; then
    chosen="$EDITOR"
  else
    for c in nvim vim nano vi; do
      if command -v "$c" >/dev/null 2>&1; then chosen="$c"; break; fi
    done
  fi
  if [[ -z "$chosen" ]]; then
    echo "No suitable editor found (tried \$EDITOR, nvim, vim, nano, vi)." >&2
    return 1
  fi

  "$chosen" "$TMP" </dev/tty
  AFTER="$(hashof "$TMP")"
  if [[ "$BEFORE" == "$AFTER" ]]; then
    echo "No changes - scratchpad left as-is."
    return 0
  fi

  if curl -fsS -X POST "${AUTH[@]}" --data-binary "@$TMP" "$BASE/dev-api/scratch" 2>/dev/null; then
    echo "Scratchpad saved."
  else
    echo "Failed to save scratchpad." >&2
    return 1
  fi
}

# ------------------------------------------------------------------ upload
do_upload() {
  local FILEPATH FNAME
  read -rp "Path to file: " FILEPATH </dev/tty
  if [[ ! -f "$FILEPATH" ]]; then
    echo "Not a regular file: $FILEPATH" >&2
    return 1
  fi
  FNAME="$(basename "$FILEPATH")"
  if curl -fsS -X POST "${AUTH[@]}" -H "X-Filename: $FNAME" \
        --data-binary "@$FILEPATH" "$BASE/dev-api/scratch/file" 2>/dev/null; then
    echo "Uploaded: $FNAME"
  else
    echo "Upload failed (wrong password or server error)." >&2
    return 1
  fi
}

# ------------------------------------------------------------------ pick
# Shared file picker: lists files, parses the selection (0=all, comma list,
# range), and fills the global PICKED array with the chosen names.
# Returns 0 with PICKED populated, or 1 if nothing to act on.
pick_files() {
  local body line name size SEL c i part a b total oldifs
  body="$(curl -fsS "${AUTH[@]}" "$BASE/dev-api/scratch/files" 2>/dev/null)" || {
    echo "Failed to list files (wrong password or server error)." >&2; return 1; }
  if [[ -z "$body" ]]; then
    echo "No files stored."; return 1
  fi

  local names=()
  echo "Files:"
  while IFS= read -r line; do
    [[ -z "$line" ]] && continue
    name="${line%|*}"
    size="${line##*|}"
    names+=("$name")
    printf '  %d) %s  (%s bytes)\n' "${#names[@]}" "$name" "$size"
  done <<< "$body"
  total="${#names[@]}"
  echo "  0) all"

  read -rp "Selection (0=all, or e.g. 1,2,4 or 2-5): " SEL </dev/tty
  local chosen=()
  if [[ "$SEL" == "0" ]]; then
    for ((i=1; i<=total; i++)); do chosen+=("$i"); done
  else
    oldifs="$IFS"; IFS=','
    for part in $SEL; do
      if [[ "$part" =~ ^([0-9]+)-([0-9]+)$ ]]; then
        a="${BASH_REMATCH[1]}"; b="${BASH_REMATCH[2]}"
        for ((i=a; i<=b; i++)); do chosen+=("$i"); done
      elif [[ "$part" =~ ^[0-9]+$ ]]; then
        chosen+=("$part")
      fi
    done
    IFS="$oldifs"
  fi

  PICKED=()
  for c in "${chosen[@]}"; do
    if (( c < 1 || c > total )); then
      echo "  #$c out of range, skipping." >&2; continue
    fi
    PICKED+=("${names[$((c-1))]}")
  done
  [[ "${#PICKED[@]}" -eq 0 ]] && { echo "Nothing selected."; return 1; }
  return 0
}

# ------------------------------------------------------------------ download
do_download() {
  pick_files || return 0
  local name
  for name in "${PICKED[@]}"; do
    # Files are served directly by nginx (no auth) at /files/scratch/<name>.
    if curl -fsSL -o "./$name" "$BASE/files/scratch/$name" 2>/dev/null; then
      echo "Downloaded: $name"
    else
      echo "Failed to download: $name" >&2
    fi
  done
}

# ------------------------------------------------------------------ delete
do_delete() {
  pick_files || return 0
  local name
  for name in "${PICKED[@]}"; do
    if curl -fsS -X DELETE "${AUTH[@]}" -H "X-Filename: $name" \
          "$BASE/dev-api/scratch/file" 2>/dev/null; then
      echo "Deleted: $name"
    else
      echo "Failed to delete: $name" >&2
    fi
  done
}

# ------------------------------------------------------------------ clip
# Scratchpad -> the clipboard actually in front of you.
do_clip() {
  local TMP
  TMP="$(mktemp)"
  if ! curl -fsSL "${AUTH[@]}" "$BASE/dev-api/scratch" -o "$TMP" 2>/dev/null; then
    rm -f "$TMP"
    echo "Failed to fetch scratchpad (wrong password or server error)." >&2
    return 1
  fi
  clip_out < "$TMP"
  rm -f "$TMP"
  echo "Scratchpad copied to clipboard."
}

# ------------------------------------------------------------------ show
do_show() {
  curl -fsSL "${AUTH[@]}" "$BASE/dev-api/scratch" 2>/dev/null || {
    echo "Failed to fetch scratchpad (wrong password or server error)." >&2
    return 1
  }
}

# ------------------------------------------------------------------ paste
# Clipboard -> scratchpad (replaces the whole buffer, like every other write).
do_paste() {
  local DATA
  DATA="$(clip_in)" || return 1
  if printf '%s' "$DATA" | curl -fsS -X POST "${AUTH[@]}" \
        --data-binary @- "$BASE/dev-api/scratch" 2>/dev/null; then
    echo "Clipboard saved to scratchpad."
  else
    echo "Failed to save scratchpad." >&2
    return 1
  fi
}

# ------------------------------------------------------------------ clear
do_clear() {
  if curl -fsS -X POST "${AUTH[@]}" --data-binary "" \
        "$BASE/dev-api/scratch" 2>/dev/null; then
    echo "Scratchpad cleared."
  else
    echo "Failed to clear scratchpad." >&2
    return 1
  fi
}

# ------------------------------------------------------------------ main
echo "-- Scratch --------------------------------"
echo "  1) clip      scratchpad -> clipboard"
echo "  2) show      scratchpad -> terminal"
echo "  3) edit      edit in \$EDITOR (exit saves)"
echo "  4) paste     clipboard -> scratchpad"
echo "  5) clear     empty the scratchpad"
echo "-- Box ------------------------------------"
echo "  6) upload    a file -> box"
echo "  7) download  box -> here"
echo "  8) delete    remove from box"
read -rp "Select [1-8]: " CHOICE </dev/tty
case "$CHOICE" in
  1) do_clip ;;
  2) do_show ;;
  3) do_edit ;;
  4) do_paste ;;
  5) do_clear ;;
  6) do_upload ;;
  7) do_download ;;
  8) do_delete ;;
  *) echo "Invalid choice." >&2; exit 1 ;;
esac
