nix-search() (
  set -euo pipefail
  local flake="${1:-nixpkgs}"; shift ||:

  trace(){
    if [[ -t 2 ]]; then
      printf >&2 "%s\n" "$@"
    fi
  }
  die() {
    printf >&2 "%s\n" "$@"
    exit 1
  }
  command -v nix  >/dev/null || die "ERROR: 'nix' not in PATH"
  command -v jq   >/dev/null || die "ERROR: 'jq' not in PATH"
  command -v fzf  >/dev/null || die "ERROR: 'fzf' not in PATH"
  command -v bat  >/dev/null || die "ERROR: 'bat' not in PATH"
  command -v tr   >/dev/null || die "ERROR: 'tr' not in PATH"
  command -v sed  >/dev/null || die "ERROR: 'sed' not in PATH"
  command -v grep >/dev/null || die "ERROR: 'grep' not in PATH"
  command -v sort >/dev/null || die "ERROR: 'sort' not in PATH"
  if [[ -t 1 ]] && ! command -v gum >/dev/null; then
    trace "WARNING: 'gum' not in PATH, no action menu will be provided"
  fi

  # local nixpkgs=$(nix eval "$flake"#path --json | jq . -r) # --raw hangs?
  local nixpkgs=$(nix flake metadata "$flake" --json | jq .path -r)
  local cachedir="${XDG_CACHE_HOME:-"$HOME/.cache"}/nix-search-sh"

  export storepath="$cachedir"/"${flake//"/"/--}"/path
  export packages_json="$cachedir"/"${flake//"/"/--}"/packages.json
  export packages_tsv="$cachedir"/"${flake//"/"/--}"/packages.tsv

  if [[ ! -f "$storepath" || "$nixpkgs" != "$(cat "$storepath")" ]]; then
    mkdir -p "$cachedir"/"$flake"

    # TODO: somehow inherit if user has configured allowUnfree and such in any file
    trace "Indexing..."
    # true || \
    (
      system="$(nix config show system)"
      set -x
      time nix-env >"$packages_json" \
        --extra-experimental-features no-url-literals \
        --option system "$system" \
        -f "$nixpkgs" \
        -qaP \
        --json \
        --meta \
        --show-trace \
        --no-allow-import-from-derivation \
        --arg config '{ allowAliases = false; }'
    )

    trace "Preprocessing..."
    trace "+ jq ..."
    time jq <"$packages_json" 'to_entries[] | [
          "--",
          .key,
          .value.meta.description // .value.meta.longDescription // "" | split("\n") | .[0],
          ({version: (.value.version)} // {}) + (.value.meta // {}),
        ] | @tsv' -r \
      | tr '0123456789' '9876543210' | sort | tr '0123456789' '9876543210' \
      > "$packages_tsv"

    printf "%s\n" "$nixpkgs" > "$storepath";
  fi

  if [[ ! -t 0 && "$?" -eq 0 ]]; then
    echo asd
    return 0
  fi

  show-package() {
    local attrpath="$(head -n1 <<<"$1")"
    printf "%s\n" "(toggle preview with 'alt-enter', scroll with '{shift,alt}-{up,down}')"
    printf "\n"

    grep -F -- $'--\t'"$attrpath"$'\t' "$packages_tsv" | cut -f4 | jq '. | [
        "version   : \(.version)",
        "homepage  : \(.homepage  // "")",
        "changelog : \(.changelog // "")",
        "unfree    : \(.unfree)",
        "broken    : \(.broken)",
        "insecure  : \(.insecure)",
        "",
        "\(.longDescription // .description)",
        "",
        "source: \(.position // "")",
        "license:", ([if (.license|type)=="array" then .license[] else .license // [][] end | "- \(.fullName // .)"] | join("\n")),
        "",
        "platforms:", ([(.platforms // [])[]|"- \(.)"]|join("\n"))
      ] | join("\n")
    ' -r | bat --style=plain --language yaml --color=always
  }

  local fzf_config=(
    --reverse
    --bind 'ctrl-a:toggle-all'
    --bind 'alt-enter:toggle-preview'
    # --bind 'shift-page-up:preview-page-up'
    # --bind 'shift-page-down:preview-page-down'
    # --bind 'ctrl-page-up:preview-page-up'
    # --bind 'ctrl-page-down:preview-page-down'
    --bind 'alt-up:preview-up'
    --bind 'alt-down:preview-down'
    --bind 'shift-up:preview-page-up'
    --bind 'shift-down:preview-page-down'
  )

  local -a attributes
  readarray -d $'\n' -t attributes < <(
    cut <"$packages_tsv" -f2-3 | tr '\n' '\0' | tr '\t' '\n' \
      | fzf --read0 --print0 --gap 1 --multi --tiebreak=begin "${fzf_config[@]}" --preview "$(declare -f show-package); show-package {}" \
      | tr '\n\0' '\t\n' | cut -f1
  )

  if [[ "${#attributes[@]}" -gt 0 ]]; then
    if [[ ! -t 1 ]] || ! command -v gum >/dev/null; then
      printf "%s\n" "${attributes[@]}"
    else
      local -a menu=(
        "print   : 'printf' the packages"
        "print2  : 'printf' the packages with flake prefixed"
        "build   : 'nix-build' the packages"
        "install : 'nix profile install' the packages"
        # "enter   : 'nix-shell' the packages and modify this environment"
        "shell   : 'nix shell ...' the packages"
        "shell2  : 'nix shell ...^*' the packages"
        "shell3  : 'nix-shell ...' the packages"
      )
      case "$(gum choose "${menu[@]}" | cut -d' ' -f1)" in
        print)
          printf "%s\n" "${attributes[@]}"
        ;;
        print2)
          printf "%s\n" "${attributes[@]/#/"$flake#"}"
        ;;
        build)
          if command -v nom-build >/dev/null; then
            eval "nom-build '$nixpkgs' ${attributes[*]/#/-A }"
          else
            eval "nix-build '$nixpkgs' ${attributes[*]/#/-A }"
          fi
        ;;
        install)
          nix profile install "${attributes[@]/#/"$flake#"}"
        ;;
        shell)
          nix shell "${attributes[@]/#/"$flake#"}"
        ;;
        shell2)
          local -a attributes_all=("${attributes[@]/%/'^*'}")
          nix shell "${attributes_all[@]/#/"$flake#"}"
        ;;
        shell3)
          eval "nix-shell '$nixpkgs' ${attributes[*]/#/-A }"
        ;;
        *)
          die "unknown option"
          exit 1
        ;;
      esac
    fi
  fi
)

# TODO: add a bash keybind, like the fzf file picker?
