#!/bin/bash
#
# Purpose : Set up the things MiniServer installs that need your input:
#           mounting your Nextcloud files and signing in to the AI agents.
#
# Each file in configure.d/ is one item. It sets TITLE and DESCRIPTION and
# defines is_configured and run_configure. It can also define is_installed;
# the item is left out when that fails. To add an item, add a file there.

# Wrapped in { ...; exit; } so bash reads the whole script up front; update
# replaces this file while it runs.
{

MINISERVER="$HOME/.local/share/MiniServer"
PATH="$HOME/.local/bin:$PATH"

# Run an agent's real command rather than its sandboxed one in sandbox/bin:
# setting an agent up writes outside its sandbox
unsandboxed() {
  "$MINISERVER/sandbox/bin/unsandboxed" "$@"
}

# Ask a yes/no question; the default is no
confirm() {
  local answer
  read -rp "$1 [y/N] " answer
  [[ "$answer" == [yY]* ]]
}

# Ask a yes/no question; the default is yes
confirm_yes() {
  local answer
  read -rp "$1 [Y/n] " answer
  [[ "$answer" != [nN]* ]]
}

usage() {
  cat << EOF
Usage: configure [item]

  configure          Show what's set up and choose what to set up
  configure <item>   Set up one item
  configure --list   Show what's set up, and the item names

EOF
}

# configure.d/30-claude.sh -> claude
item_name() {
  local name
  name="$(basename "$1" .sh)"
  echo "${name#[0-9][0-9]-}"
}

# Prints "<state>|<title>|<description>"; state is done, todo or absent
item_info() {
  (
    source "$1"
    if declare -f is_installed > /dev/null && ! is_installed &> /dev/null; then
      echo "absent||"
    elif is_configured &> /dev/null; then
      echo "done|$TITLE|$DESCRIPTION"
    else
      echo "todo|$TITLE|$DESCRIPTION"
    fi
  )
}

configure_item() {
  (
    source "$1"
    echo
    echo -e "\e[1m$TITLE\e[0m"
    run_configure
  )
  local status=$?
  if [ $status -ne 0 ]; then
    echo -e "\e[31m$(item_name "$1") was not set up.\e[0m"
  fi
  return $status
}

# Fill ITEMS, STATES, TITLES and DESCRIPTIONS with the installed items
load_items() {
  local file state title description
  ITEMS=() STATES=() TITLES=() DESCRIPTIONS=()
  for file in "$MINISERVER"/configure.d/*.sh; do
    [ -f "$file" ] || continue
    IFS='|' read -r state title description < <(item_info "$file")
    [ "$state" = absent ] && continue
    ITEMS+=("$file") STATES+=("$state") TITLES+=("$title") DESCRIPTIONS+=("$description")
  done
}

show_items() {
  local i mark
  for i in "${!ITEMS[@]}"; do
    if [ "${STATES[$i]}" = done ]; then
      mark="\e[32mdone\e[0m "
    else
      mark="\e[33mto do\e[0m"
    fi
    printf "  %2d) $mark  %-22s %s\n" $((i + 1)) "${TITLES[$i]}" "${DESCRIPTIONS[$i]}"
  done
}

case "$1" in
  "") ;;
  -h|--help)
    usage
    exit 0 ;;
  -l|--list)
    load_items
    for i in "${!ITEMS[@]}"; do
      printf '%-6s %-14s %s\n' "${STATES[$i]/todo/to do}" "$(item_name "${ITEMS[$i]}")" "${TITLES[$i]}"
    done
    exit 0 ;;
  *)
    for file in "$MINISERVER"/configure.d/*.sh; do
      if [ "$(item_name "$file")" = "$1" ]; then
        configure_item "$file"
        exit
      fi
    done
    echo "No item named $1. These are: configure --list"
    exit 2 ;;
esac

while true; do
  load_items
  echo
  echo "MiniServer configuration"
  echo
  show_items
  echo
  echo "   a) Set up everything still to do"
  echo "   q) Quit"
  echo
  read -rp "Choose: " choice || exit 0

  case "$choice" in
    q|Q|"")
      exit 0 ;;
    a|A)
      for i in "${!ITEMS[@]}"; do
        [ "${STATES[$i]}" = todo ] && configure_item "${ITEMS[$i]}"
      done ;;
    *)
      if [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#ITEMS[@]} )); then
        configure_item "${ITEMS[$((choice - 1))]}"
      else
        echo "Choose a number from the list, a or q."
      fi ;;
  esac
done
}
