# =============================================================================
# cb — shared clipboard convenience wrapper
#
# Source this file in your ~/.bashrc:
#   source /path/to/cb.bash
#
# Required environment variables:
#   CB_HOST      Server base URL          e.g.  http://localhost:8080
#   CB_COPY_CMD  Clipboard sink command   e.g.  wl-copy
#                                               xclip -selection clipboard
#                                               pbcopy
#
# Dependencies: curl, jq, fzf
# =============================================================================


# ── internal helpers (defined at top level so completion can reuse them) ──────

_cb_fetch_json() {
    # Fetch /api/buffers JSON; prints to stdout.
    curl -sf "${CB_HOST}/api/buffers"
}

_cb_sorted_names() {
    # Print buffer names sorted newest-first, one per line.
    # Accepts JSON on stdin or as $1.
    if [[ -n "$1" ]]; then
        printf '%s' "$1"
    else
        _cb_fetch_json
    fi | jq -r 'sort_by(.updated_at) | reverse | .[].name'
}

_cb_fzf_pick() {
    # Interactive fzf buffer picker with content preview.
    # Prints the selected name (empty string if cancelled).
    # Works both at runtime and inside bash completion (reads /dev/tty).
    local json="$1"
    local tmp
    tmp=$(mktemp) || return 1
    printf '%s' "$json" > "$tmp"

    _cb_sorted_names "$json" \
        | fzf --layout=reverse \
              --preview "jq -r --arg n {} '.[] | select(.name == \$n) | .content' $(printf '%q' "$tmp")" \
              --preview-window=right:60%:wrap
    local exit_code=$?
    rm -f "$tmp"
    return $exit_code
}


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

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

    # ── usage ──────────────────────────────────────────────────────────────
    if [[ $# -eq 0 ]]; then
        cat <<'EOF'
cb — shared clipboard

  cb copy [name]           Copy a buffer to clipboard.
                           Omit name to pick interactively with fzf.
  cb paste [content]       Write to a new buffer (auto-named by server).
                           Omit content to read from stdin.
  cb rename <name> <new>   Rename a buffer.
                           Tab-complete <name> with fzf.
  cb delete <name>         Delete a buffer.
                           Tab-complete <name> with fzf.

Environment:
  CB_HOST      Server URL        e.g.  http://localhost:8080
  CB_COPY_CMD  Clipboard command e.g.  wl-copy
                                       xclip -selection clipboard
                                       pbcopy
EOF
        return 0
    fi

    local subcmd="$1"; shift

    case "$subcmd" in

        # ── copy ────────────────────────────────────────────────────────────
        copy)
            local name="$1"
            if [[ -z "$name" ]]; then
                local json
                json=$(_cb_fetch_json) \
                    || { printf 'cb: failed to reach %s\n' "$host" >&2; return 1; }
                name=$(_cb_fzf_pick "$json")
                [[ -z "$name" ]] && return 0   # user cancelled
            fi
            curl -sf "$host/$name" | $copy_cmd
            ;;

        # ── paste ───────────────────────────────────────────────────────────
        paste)
            local content
            if [[ $# -gt 0 ]]; then
                content="$*"
            else
                content=$(cat)
            fi
            # Pipe through @- so leading '@' in content is never misread as a filename.
            printf '%s' "$content" \
                | curl -sf -X PUT --data-binary @- "$host/"
            printf '\n'
            ;;

        # ── rename ──────────────────────────────────────────────────────────
        rename)
            local current="$1" new_name="$2"
            if [[ -z "$current" ]]; then
                local json
                json=$(_cb_fetch_json) \
                    || { printf 'cb: failed to reach %s\n' "$host" >&2; return 1; }
                current=$(_cb_fzf_pick "$json")
                [[ -z "$current" ]] && return 0
            fi
            if [[ -z "$new_name" ]]; then
                printf 'New name for "%s": ' "$current" >&2
                read -r new_name
                [[ -z "$new_name" ]] && return 0
            fi
            printf '%s' "$new_name" \
                | curl -sf -X PATCH --data-binary @- "$host/$current"
            printf '\n'
            ;;

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

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


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

_cb_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 "copy paste rename delete" -- "$cur"))
        return
    fi

    # All further completions need CB_HOST
    [[ -z "${CB_HOST:-}" ]] && return

    # ── fzf picker for use inside completion ────────────────────────────
    # Reads the tty directly so it can take over the terminal mid-completion.
    _cb_complete_fzf() {
        local json
        json=$(curl -sf "${CB_HOST}/api/buffers" 2>/dev/null) || return
        _cb_fzf_pick "$json"
    }

    case "$subcmd" in

        copy)
            if [[ $COMP_CWORD -eq 2 ]]; then
                local selected
                selected=$(_cb_complete_fzf)
                [[ -n "$selected" ]] && COMPREPLY=("$selected")
            fi
            ;;

        rename)
            # Tab on the first arg opens fzf; second arg is typed by the user.
            if [[ $COMP_CWORD -eq 2 ]]; then
                local selected
                selected=$(_cb_complete_fzf)
                [[ -n "$selected" ]] && COMPREPLY=("$selected")
            fi
            ;;

        delete)
            if [[ $COMP_CWORD -eq 2 ]]; then
                local selected
                selected=$(_cb_complete_fzf)
                [[ -n "$selected" ]] && COMPREPLY=("$selected")
            fi
            ;;

    esac
}

complete -F _cb_complete cb
