#!/usr/bin/env bash
#
# Dotfiles manager and install helper
# (c) Ismo Vuorinen <https://github.com/ivuorinen> 2022
# Licensed under MIT, see LICENSE
#
# shellcheck source-path=$HOME/.dotfiles/local/bin
#
# Helper variables, override with ENVs like `VERBOSE=1 dfm help`
: "${VERBOSE:=0}"
: "${DOTFILES:=$HOME/.dotfiles}"
: "${BREWFILE:=$DOTFILES/config/homebrew/Brewfile}"
: "${HOSTFILES:=$DOTFILES/hosts}"

SCRIPT=$(basename "$0")

VERSION_NVM="v0.39.5"

export DOTFILES="$HOME/.dotfiles"
# shellcheck source=./../../scripts/shared.sh
source "$HOME/.dotfiles/scripts/shared.sh"
source "$DOTFILES/config/exports"
source "$DOTFILES/config/alias"
source "$DOTFILES/config/functions"

# Loads configs for better installation experience
x-load-configs

function section_install
{
  USAGE_PREFIX="$SCRIPT install <command>"

  MENU=(
    "all:Installs everything in the correct order"
    "antigen:Updates the antigen.zsh file"
    "cargo:Install rust/cargo packages"
    "cheat-databases:Install cheat external cheatsheet databases"
    "composer:Install composer"
    "dotenv:Install dotenv-linter"
    "fonts:Install programming fonts"
    "gh:Install GitHub CLI Extensions"
    "go:Install Go Packages"
    "imagick:Install ImageMagick CLI"
    "starship:Install starship.rs"
    "macos:Setup nice macOS defaults"
    "neofetch:Install neofetch"
    "nvm:Install Node Version Manager (nvm)"
    "nvm-latest:Install latest lts node using nvm"
    "npm:Install NPM Packages"
    "ntfy:Install ntfy"
    "ohmybash:Install oh-my-bash"
    "pip:Install pip/python packages"
    "z:Install z"
  )

  case "$1" in
    all)
      msgr msg "Starting to install all and reloading configurations..."
      x-load-configs
      $0 install macos
      $0 install fonts
      $0 install antigen
      $0 brew install
      $0 install ohmyposh
      $0 install ohmybash
      $0 install pip
      $0 install cargo
      $0 install composer
      $0 install dotenv
      $0 install fzf
      $0 install gh
      $0 install go
      $0 install cheat-databases
      $0 install imagick
      $0 install neofetch
      $0 install nvm
      $0 install npm
      $0 install ntfy
      $0 install z
      msgr msg "Reloading configurations again..."
      x-load-configs
      msgr yay "All done!"
      ;;
    antigen)
      msg "Installing antigen..."
      curl -sSfL git.io/antigen -o "$DOTFILES/local/bin/antigen.zsh" \
        && msg_yay "New antigen installed!"
      ;;
    cargo)
      msg "Installing cargo packages..."
      bash "$DOTFILES/scripts/install-cargo-packages.sh" \
        && msg_yay "cargo packages installed!"
      ;;
    cheat-databases)
      msg "Installing cheat databases..."
      for database in "$DOTFILES"/scripts/install-cheat-*; do
        bash "$database" \
          && msg_yay "Cheat: $database run"
      done
      ;;
    composer)
      msg "Installing composer..."
      bash "$DOTFILES/scripts/install-composer.sh" \
        && msg_yay "composer installed!"
      ;;
    dotenv)
      msg "Installing dotenv-linter..."
      curl -sSfL \
        https://raw.githubusercontent.com/dotenv-linter/dotenv-linter/master/install.sh \
        | sh -s -- -b "$XDG_BIN_HOME" \
        && msg_yay "dotenv-linter installed!"
      ;;
    fonts)
      msg "Installing fonts..."
      bash "$DOTFILES/scripts/install-fonts.sh" \
        && msg_yay "Installed fonts!"
      ;;
    fzf)
      msg "Installing fzf..."
      bash "$DOTFILES/scripts/install-fzf.sh" \
        && msg_yay "fzf installed!"
      ;;
    gh)
      msg "Installing GitHub CLI Extensions..."
      bash "$DOTFILES/scripts/install-gh-extensions.sh" \
        && msg_yay "github cli extensions installed!"
      ;;
    go)
      msg "Installing Go Packages..."
      bash "$DOTFILES/scripts/install-go-packages.sh" \
        && msg_yay "go packages installed!"
      ;;
    imagick)
      msg "Installing ImageMagick CLI..."
      curl -L https://imagemagick.org/archive/binaries/magick > "$XDG_BIN_HOME/magick" \
        && chmod +x "$XDG_BIN_HOME/magick" \
        && msg_yay "imagick installed!"
      ;;
    starship)
      msg "Installing starship.rs..."
      curl -sS https://starship.rs/install.sh | sh -s -- \
        --bin-dir ~/.local/bin \
        --yes \
        && msg_yay "starship installed!"
      ;;
    macos)
      msg "Setting up macOS defaults..."
      bash "$DOTFILES/scripts/set-macos-defaults.sh" \
        && msg_yay "Brewfile defined apps has been installed!"
      ;;
    neofetch)
      msg "Installing neofetch..."
      bash "$DOTFILES/scripts/install-neofetch.sh" \
        && msg_yay "neofetch installed!"
      ;;
    nvm)
      msg "Installing nvm..."
      curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/$VERSION_NVM/install.sh" | bash
      git checkout "$DOTFILES/base/zshrc"
      git checkout "$DOTFILES/base/bashrc"
      $0 install nvm-latest
      msg_yay "nvm installed!"
      ;;
    nvm-latest)
      msg "Installing latest lts node..."
      if [ -n "$NVM_DIR" ]; then
        [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
      fi
      nvm install --lts --latest-npm --default
      git checkout "$DOTFILES/base/zshrc"
      git checkout "$DOTFILES/base/bashrc"
      msg_yay "latest lts node installed!"
      ;;
    npm)
      msg "NPM Packages install started..."
      bash "$DOTFILES/scripts/install-npm-packages.sh" \
        && msg_yay "NPM Packages have been installed!"
      ;;
    ntfy)
      msg "ntfy install started..."
      bash "$DOTFILES/scripts/install-ntfy.sh" \
        && msg_yay "ntfy installed!"
      ;;
    ohmybash)
      msg "oh-my-bash install started..."
      bash "$DOTFILES/scripts/install-ohmybash.sh" \
        && msg_yay "oh-my-bash installed!"
      ;;
    ohmyposh)
      msg "oh-my-posh install started..."
      bash "$DOTFILES/scripts/install-ohmyposh.sh" \
        && msg_yay "oh-my-posh installed!"
      ;;
    pip)
      msg "pip install started..."
      bash "$DOTFILES/scripts/install-pip-packages.sh"
      ;;
    z)
      msg "Installing z..."
      bash "$DOTFILES/scripts/install-z.sh" \
        && msg_yay "z has been installed!"
      ;;
    *) menu_usage "$USAGE_PREFIX" "${MENU[@]}" ;;
  esac
}

function section_brew
{
  USAGE_PREFIX="$SCRIPT brew <command>"

  MENU=(
    "install:Installs items defined in Brewfile"
    "update:Updates and upgrades brew packages"
    "updatebundle:Updates Brewfile with descriptions"
    "autoupdate:Setups brew auto-update and runs it immediately"
  )

  x-have brew && {
    case "$1" in
      install)
        brew bundle install --file="$BREWFILE" --force --quiet && msg_yay "Done!"
        ;;
      update)
        brew update && brew outdated && brew upgrade && brew cleanup
        msg_yay "Done!"
        ;;
      updatebundle)
        # Updates .dotfiles/homebrew/Brewfile with descriptions
        brew bundle dump \
          --force \
          --file="$BREWFILE" \
          --describe && msg_yay "Done!"
        ;;
      autoupdate)
        brew autoupdate delete
        brew autoupdate start 43200 --upgrade --cleanup --immediate
        ;;
      *)
        menu_usage "$USAGE_PREFIX" "${MENU[@]}"
        ;;
    esac
  }

  ! x-have brew && menu_section "$USAGE_PREFIX" "brew not available on this system"
}

function section_helpers
{
  USAGE_PREFIX="$SCRIPT helpers <command>"
  MENU=(
    "path:Show \$PATH dir by dir"
  )

  case "$1" in
    path)
      # shellcheck disable=2001
      for i in $(echo "$PATH" | sed 's/:/ /g'); do echo "$i"; done
      ;;
    *) menu_usage "$USAGE_PREFIX" "${MENU[@]}" ;;
  esac
}

function section_docs
{
  USAGE_PREFIX="$SCRIPT docs <command>"

  MENU=(
    "tmux:Update tmux keybindings documentation"
  )

  case "$1" in
    tmux) bash "$DOTFILES/local/bin/x-dfm-docs-xterm-keybindings" ;;
    *) menu_usage "$USAGE_PREFIX" "${MENU[@]}" ;;
  esac
}

function section_dotfiles
{
  USAGE_PREFIX="$SCRIPT dotfiles <command>"

  MENU=(
    "fmt:Run all formatters"
    "yamlfmt:Run yamlfmt to all dotfiles, which are in our control"
    "shfmt:Run shfmt to all dotfiles"
    "reset_all:Reset everything, runs all configured reset actions"
    "reset_nvim:Resets nvim. Deletes caches, removes nvim folders and relinks nvim folders"
  )

  case "$1" in
    fmt)
      msg_ok "Running all formatters"
      $0 dotfiles yamlfmt
      $0 dotfiles shfmt
      msg_done "...done!"
      ;;
    reset_all)
      msg_ok "Running all reset commands"
      $0 dotfiles reset_nvim
      ;;
    reset_nvim)
      rm -rf \
        ~/.local/share/nvim \
        ~/.local/state/nvim \
        ~/.cache/nvim \
        ~/.config/nvim
      msg_ok "Deleted old nvim files (share, state and cache + config)"
      ln -s "$DOTFILES/config/nvim" ~/.config/nvim
      msg_ok "Linked nvim and astronvim"
      x-have npm && $0 install npm
      msg_ok "Installed packages"
      msg_done "nvim reset!"
      ;;
    yamlfmt)
      # format yaml files
      x-have yamlfmt && yamlfmt -conf "$DOTFILES/.yamlfmt"
      ! x-have yamlfmt && msg_err "yamlfmt not found"
      ;;
    shfmt)
      # Format shell scripts according to following rules.
      fd --full-path "$DOTFILES" -tx \
        -E '*.pl' -E '*.php' -E '*.py' -E '*.zsh' -E 'plugins' -E 'fzf' -E 'dotbot' \
        -x shfmt \
        --language-dialect bash \
        --func-next-line --list --write \
        --indent 2 --case-indent --space-redirects \
        --binary-next-line {} \;
      msg_yay "dotfiles have been shfmt formatted!"
      ;;
    *) menu_usage "$USAGE_PREFIX" "${MENU[@]}" ;;
  esac
}

function section_check
{
  USAGE_PREFIX="$SCRIPT check <command>"
  X_HOSTNAME=$(hostname)
  X_ARCH=$(uname)

  MENU=(
    "arch <arch>:Empty <arch> returns current. Exit code 0=match to current, 1=no match."
    "host <host>:Empty <host> returns current. Exit code 0=match to current, 1=no match."
  )

  case "$1" in
    a | arch)
      [[ "$2" = "" ]] && echo "$X_ARCH" && exit 0
      [[ $X_ARCH = "$2" ]] && exit 0 || exit 1
      ;;
    h | host | hostname)
      [[ "$2" = "" ]] && echo "$X_HOSTNAME" && exit 0
      [[ $X_HOSTNAME = "$2" ]] && exit 0 || exit 1
      ;;
    *) menu_usage "$USAGE_PREFIX" "${MENU[@]}" ;;
  esac
}

# Secret menu for visual tests
function section_tests
{
  USAGE_PREFIX="$SCRIPT tests <command>"

  MENU=(
    "msg:List all log functions from shared.sh"
  )

  case "$1" in
    msg)
      msg "msg"
      msg_done "msg_done"
      msg_done_suffix "msg_done_suffix"
      msg_err "msg_err"
      msg_nested "msg_nested"
      msg_nested_done "msg_nested_done"
      msg_ok "msg_ok"
      msg_prompt "msg_prompt"
      msg_prompt_done "msg_prompt_done"
      msg_run "msg_run" "second_param"
      msg_run_done "msg_run_done" "second_param"
      msg_warn "msg_warn"
      msg_yay "msg_yay"
      msg_yay_done "msg_yay_done"
      ;;
    *) menu_usage "$USAGE_PREFIX" "${MENU[@]}" ;;
  esac
}

function usage
{
  echo ""
  msg_prompt "Usage: $SCRIPT <section> <command>"
  echo $"  Empty <command> prints <section> help."
  echo ""
  section_install
  echo ""
  section_brew
  echo ""
  section_check
  echo ""
  section_dotfiles
  echo ""
  section_docs
  echo ""
  section_helpers
}

# The main loop. first keyword after $0 triggers section, or help.
case "$1" in
  install) section_install "$2" ;;
  brew) section_brew "$2" ;;
  check) section_check "$2" ;;
  dotfiles) section_dotfiles "$2" ;;
  helpers) section_helpers "$2" ;;
  docs) section_docs "$2" ;;
  tests) section_tests "$2" ;;
  *) usage && exit 0 ;;
esac
