# =============================================================================
# fb — filebox convenience wrapper
#
# Source this file in your ~/.bashrc:
#   source /path/to/fb.sh
#
# Required environment variables:
#   CB_HOST      Server base URL          e.g.  http://localhost:8080
#
# Dependencies: curl, jq, fzf
# =============================================================================


# ── internal helpers ─────────────────────────────────────────────────────────

_fb_fetch_json() {
    curl -sf "${CB_HOST}/api/files"
}

_fb_sorted_names() {
    if [[ -n "$1" ]]; then
        printf '%s' "$1"
    else
        _fb_fetch_json
    fi | jq -r 'sort_by(.uploaded_at) | reverse | .[].name'
}

_fb_format_size() {
    local size=$1
    if (( size < 1024 )); then
        printf '%d B' "$size"
    elif (( size < 1048576 )); then
        printf '%d KB' "$(( size / 1024 ))"
    elif (( size < 1073741824 )); then
        printf '%d MB' "$(( size / 1048576 ))"
    else
        printf '%d GB' "$(( size / 1073741824 ))"
    fi
}

_fb_fzf_pick() {
    local json="$1"
    local tmp
    tmp=$(mktemp) || return 1
    printf '%s' "$json" > "$tmp"

    # Build display lines: "name  (size)"
    local display_tmp
    display_tmp=$(mktemp) || { rm -f "$tmp"; return 1; }
    jq -r 'sort_by(.uploaded_at) | reverse | .[] | "\(.name)\t\(.size)"' "$tmp" \
        | while IFS=$'\t' read -r name size; do
            printf '%s  (%s)\n' "$name" "$(_fb_format_size "$size")"
        done > "$display_tmp"

    local selected
    selected=$(cat "$display_tmp" \
        | fzf --layout=reverse \
              --delimiter='  ' \
              --preview "
                  name=\$(echo {} | sed 's/  (.*//')
                  tmp=\$(mktemp /tmp/fb_preview.XXXXXX)
                  trap 'rm -f \"\$tmp\"' EXIT
                  curl -sf \"${CB_HOST}/files/\${name}\" -o \"\$tmp\" 2>/dev/null

                  if [ ! -s \"\$tmp\" ]; then
                      echo '[empty file]'
                  elif LC_ALL=C tr -d '\\0' < \"\$tmp\" | cmp -s - \"\$tmp\"; then
                      # No null bytes — treat as text
                      if command -v bat >/dev/null 2>&1; then
                          bat --style=plain --color=always --file-name=\"\$name\" \"\$tmp\"
                      else
                          head -80 \"\$tmp\"
                      fi
                  else
                      # Has null bytes — binary file
                      ext=\$(echo \"\$name\" | sed 's/.*\.//' | tr '[:upper:]' '[:lower:]')
                      case \"\$ext\" in
                          jpg|jpeg|png|gif|bmp|webp|tiff|ico)
                              if command -v chafa >/dev/null 2>&1; then
                                  chafa -s \"\${FZF_PREVIEW_COLUMNS:-60}x\${FZF_PREVIEW_LINES:-20}\" \"\$tmp\" 2>/dev/null
                              elif command -v timg >/dev/null 2>&1; then
                                  timg -g\"\${FZF_PREVIEW_COLUMNS:-60}x\${FZF_PREVIEW_LINES:-20}\" \"\$tmp\" 2>/dev/null
                              else
                                  echo '[image]'
                                  echo 'Install chafa or timg for image previews'
                              fi
                              ;;
                          pdf)
                              if command -v pdftotext >/dev/null 2>&1; then
                                  pdftotext -l 3 \"\$tmp\" - 2>/dev/null | head -80
                              else
                                  echo '[pdf]'
                                  echo 'Install poppler (pdftotext) for PDF previews'
                              fi
                              ;;
                          *)
                              echo '[binary file]'
                              ;;
                      esac
                  fi
              " \
              --preview-window=right:60%:wrap)

    local exit_code=$?
    rm -f "$tmp" "$display_tmp"

    # Strip the size suffix to return just the name
    if [[ -n "$selected" ]]; then
        printf '%s' "$selected" | sed 's/  (.*//'
    fi
    return $exit_code
}


# ── main function ────────────────────────────────────────────────────────────

fb() {
    local host="${CB_HOST:?CB_HOST is not set — e.g. export CB_HOST=http://localhost:8080}"

    if [[ $# -eq 0 ]]; then
        cat <<'EOF'
fb — filebox

  fb send <file> [file...]   Upload files to the server.
  fb get [name]              Download a file.
                             Omit name to pick interactively with fzf.
  fb delete [name]           Delete a file from the server.
                             Omit name to pick interactively with fzf.

Environment:
  CB_HOST      Server URL        e.g.  http://localhost:8080
EOF
        return 0
    fi

    local subcmd="$1"; shift

    case "$subcmd" in

        # ── send ──────────────────────────────────────────────────────────
        send)
            if [[ $# -eq 0 ]]; then
                printf 'Usage: fb send <file> [file...]\n' >&2
                return 1
            fi
            for f in "$@"; do
                if [[ ! -f "$f" ]]; then
                    printf 'fb: file not found: %s\n' "$f" >&2
                    continue
                fi
                curl -sf -F "file=@$f" "$host/files/"
            done
            ;;

        # ── get ───────────────────────────────────────────────────────────
        get)
            local name="$1"
            if [[ -z "$name" ]]; then
                local json
                json=$(_fb_fetch_json) \
                    || { printf 'fb: failed to reach %s\n' "$host" >&2; return 1; }
                name=$(_fb_fzf_pick "$json")
                [[ -z "$name" ]] && return 0
            fi

            local outname="$name"

            if [[ -e "$outname" ]]; then
                printf 'File "%s" already exists. Overwrite? [y/N] ' "$outname" >&2
                local answer
                read -r answer
                case "$answer" in
                    [yY]|[yY][eE][sS]) ;;
                    *)
                        printf 'Enter a new name (without extension to keep "%s"): ' "${name##*.}" >&2
                        read -r outname
                        [[ -z "$outname" ]] && { printf 'fb: cancelled\n' >&2; return 0; }
                        # If user didn't provide an extension, use the original's
                        if [[ "$outname" != *.* ]]; then
                            local ext="${name##*.}"
                            if [[ "$ext" != "$name" ]]; then
                                outname="${outname}.${ext}"
                            fi
                        fi
                        ;;
                esac
            fi

            curl -sf "$host/files/$name" -o "$outname" \
                && printf 'Downloaded: %s\n' "$outname" >&2 \
                || printf 'fb: download failed\n' >&2
            ;;

        # ── delete ────────────────────────────────────────────────────────
        delete)
            local name="$1"
            if [[ -z "$name" ]]; then
                local json
                json=$(_fb_fetch_json) \
                    || { printf 'fb: failed to reach %s\n' "$host" >&2; return 1; }
                name=$(_fb_fzf_pick "$json")
                [[ -z "$name" ]] && return 0
            fi
            curl -sf -X DELETE "$host/files/$name"
            printf '\n'
            ;;

        *)
            printf 'fb: unknown subcommand "%s"\n' "$subcmd" >&2
            printf 'Run "fb" with no arguments for usage.\n' >&2
            return 1
            ;;
    esac
}


# ── bash completion ──────────────────────────────────────────────────────────

_fb_complete() {
    local cur="${COMP_WORDS[COMP_CWORD]}"
    local subcmd="${COMP_WORDS[1]:-}"
    COMPREPLY=()

    # word 1: complete subcommand names
    if [[ $COMP_CWORD -eq 1 ]]; then
        COMPREPLY=($(compgen -W "send get delete" -- "$cur"))
        return
    fi

    [[ -z "${CB_HOST:-}" ]] && return

    case "$subcmd" in

        send)
            # Normal file completion
            COMPREPLY=($(compgen -f -- "$cur"))
            ;;

        get)
            if [[ $COMP_CWORD -eq 2 ]]; then
                local json selected
                json=$(curl -sf "${CB_HOST}/api/files" 2>/dev/null) || return
                selected=$(_fb_fzf_pick "$json")
                [[ -n "$selected" ]] && COMPREPLY=("$selected")
            fi
            ;;

        delete)
            if [[ $COMP_CWORD -eq 2 ]]; then
                local json selected
                json=$(curl -sf "${CB_HOST}/api/files" 2>/dev/null) || return
                selected=$(_fb_fzf_pick "$json")
                [[ -n "$selected" ]] && COMPREPLY=("$selected")
            fi
            ;;

    esac
}

complete -F _fb_complete fb
