#!/usr/bin/env bash
#
# A utility script to get attributes for an entry. getAttr.sh shows a dialog with
# all of the entries in a DB; the user selectls one and is then shown all of the
# attributes for that entry. The user selects one of THOSE, and then the script
# outputs the value of that attribute dependiyng on the script arguments.
# getAtr.sh can put the value in the system clipboard; it can type it (using
# xdotool); or it can simply print it to STDOUTi.
#
# Depends on
# - rofi or fzf (one or both)
# - xsel
# - xdotool
# - colmun, from util-linux (on Arch)

# Number of milliseconds between keystrokes, used by xdotool. 150 is a decent WPM
STROKE=150

function _rook() {
  rook "$@"
}
if type keyctl>/dev/null; then
  rp=$(keyctl list @s | grep rookpin | cut -d: -f1)
  if [[ -n "$rp" ]]; then
    function _rook() {
      rook -k "$@"
    }
  fi
fi

function prompt() {
  rofi -dmenu -p $1 -i
}
function output() {
  printf "%s\n" $(<<<"$@" xaggs)
}
function _clipboard() {
  read line
  printf "%s\n" $line
}
function usage() {
  printf "USAGE: %s [args]\n" "$0"
  printf "If no args are provided, rofi will be used for prompting and the selected\n"
  printf "value will be printed to STDOUT\n"
  printf "  -a   Try to autodetect the site first\n"
  printf "  -h   Print this help\n"
  printf "  -f   Use fzf instead of rofi\n"
  printf "  -t   The value is typed (via xdotool)\n"
  printf "  -c   The value is copied to the clipboard\n"
  printf "  -u   Grab the entry's user name\n"
  printf "  -p   Grab the entry's password\n"
  printf "  -o   Grab the entry's OTP\n"
}
while getopts aftcupo opt; do
  case $opt in
    a)
      ## Get the window under the cursor
      WID=$(xdotool getactivewindow)
      ## Search for the window title in the DB
      NAME=$(xdotool getwindowname $WID)
      # LUAKIT hack, because its behavior can be really stupid
      APP=$(xprop -id ${WID} WM_CLASS | rg Luakit)
      ;;
    f)
      function prompt() {
        fzf
      }
      ;;
    t)
      function output() {
        sleep 0.5
        xdotool type --delay $STROKE "$(<<<$@ xargs)"
      }
      ;;
    c)
      CLIP=true
      if type xsel > /dev/null ; then
        function _clipboard() {
          xsel -b
        }
      elif type xclip > /dev/null ; then
        function _clipboard() {
          xclip -selection clipboard
        }
      fi
      function output() {
        <<<"$@" xargs | _clipboard
      }
      ;;
    h)
      usage
      exit 0
      ;;
    u)
      GET='user'
      ;;
    p)
      GET='password'
      ;;
    o)
      GET='otp'
      ;;
    *)
      usage
      exit 1
      ;;
  esac
done

GOTP="Generate OTP"

ENTRY=""
if [[ -n "$NAME" ]]; then
  typeset -a LNS
  typeset -a ENTRIES
  while read -r line; do
    LNS+=("$line")
    ENTRY=$(<<<"$line" rg '^\d+\s+([^\s]*\s+.*$)' -or '$1') && ENTRIES+=("$E") && printf "added %s\n" "$E"
  done < <(_rook match "$NAME")

  if [[ ${#ENTRIES[@]} -gt 1 ]]; then
    E=$(printf "%s\n" "${ENTRIES[@]}" | rofi -dmenu -i -p "Which entry?")
  elif [[ ${#ENTRIES[@]} -eq 0 ]]; then
    printf "nothing found\n"
    exit 1
  else
    ENTRY="${ENTRIES[1]}"
  fi
else
  IFS=$'\t' ENTRY=($(_rook ls | column -s $'\t' -o $'\t' -t -H 1 | prompt Entry | sed -E 's/\t +/\t/g;s/ +\t/\t/g'))
  [[ $? -ne 0 || -z "$ENTRY" ]] && exit
fi

case "$GET" in
  user)
    _rook show -nu "${ENTRY[@]}" | _clipboard
    exit
    ;;
  password)
    _rook show -np "${ENTRY[@]}" | _clipboard
    exit
    ;;
  otp)
    _rook show -no "${ENTRY[@]}" | _clipboard
    exit
    ;;
  *)
    # INTENTIONAL NOP
    ;;
esac

typeset -A KEYS
while read -r line; do
  [[ -z "$SKIP" ]] && SKIP=1 && continue
  key="${line%%:*}"
  if [[ -n "$key" && "$key" != "${line#*:}" ]]; then
    val="$(<<<${line#*:} xargs)"
    KEYS+=(${key} ${val})
  fi
  shopt -s nocasematch
  [[ "$key" =~ "otp" ]] && KEYS+=("$GOTP")
  shopt +s nocasematch
done < <(_rook show "${ENTRY[@]}")

[[ "${#KEYS[@]}" -eq 0 ]] && printf "No matches" && exit 1


SEL=$(printf "%s\n" "${!KEYS[@]}" | sort | prompt Key)
[[ $? -ne 0 ]] && exit

case "$SEL" in
  "$GOTP")
    VAL=$(_rook show -o "${ENTRY[@]}")
    ;;
  *)
    VAL="${KEYS[$SEL]}"
    [[ "${VAL}" = '******' ]] && VAL="$(_rook show -f "$SEL" "${ENTRY[@]}")"
    ;;
esac

output "${VAL}"
