#!/usr/bin/env bash

set -o pipefail

# ============================================================
# Hastebin / pste.us uploader
#
# Dependencies:
#   curl jq gum fzf qrencode
#
# Clipboard:
#   wl-copy / xclip / xsel / pbcopy
# ============================================================

UPLOAD_URL="https://pste.us/documents"
BASE_URL="https://pste.us"

# Catppuccin-ish colors
BLUE="#89b4fa"
GREEN="#a6e3a1"
RED="#f38ba8"
YELLOW="#f9e2af"
CYAN="#89dceb"
MAUVE="#cba6f7"
TEXT="#cdd6f4"
DIM="#6c7086"

TMP_RESPONSE=""
TMP_PROGRESS=""

# ------------------------------------------------------------
# Cleanup
# ------------------------------------------------------------

cleanup() {
    [[ -n "$TMP_RESPONSE" && -f "$TMP_RESPONSE" ]] && rm -f "$TMP_RESPONSE"
    [[ -n "$TMP_PROGRESS" && -f "$TMP_PROGRESS" ]] && rm -f "$TMP_PROGRESS"
}

trap cleanup EXIT
trap 'exit 130' INT TERM

# ------------------------------------------------------------
# Helpers
# ------------------------------------------------------------

error() {
    gum style \
        --foreground "$RED" \
        --border double \
        --border-foreground "$RED" \
        --padding "0 2" \
        "✗ $1"
    exit 1
}

# ------------------------------------------------------------
# Dependencies
# ------------------------------------------------------------

for cmd in curl jq gum fzf; do
    command -v "$cmd" &>/dev/null || \
        error "Missing dependency: $cmd"
done

# ------------------------------------------------------------
# Arguments
# ------------------------------------------------------------

FILE_PATH="${1:-}"

while [[ $# -gt 0 ]]; do
    case "$1" in
        -h|--help)
            cat <<'EOF'
Usage:
  hastebin [FILE]

Examples:
  hastebin
  hastebin file.txt
EOF
            exit 0
            ;;
        -*)
            error "Unknown option: $1"
            ;;
        *)
            FILE_PATH="$1"
            shift
            ;;
    esac
done

# ------------------------------------------------------------
# File picker
# ------------------------------------------------------------

if [[ -z "$FILE_PATH" ]]; then
    FILE_PATH=$(
        find . -maxdepth 1 -type f -printf '%f\n' |
        fzf \
            --prompt="   Select file to upload: " \
            --border \
            --reverse \
            --header="Use ↑/↓ to select • Enter to confirm" \
            --pointer="➜" \
            --color="bg+:#1e1e2e,bg:#181825,spinner:#f5c2e7,hl:#f38ba8,fg:#cdd6f4,header:#89b4fa,info:#f9e2af,pointer:#a6e3a1,marker:#f5c2e7,fg+:#cdd6f4,prompt:#89b4fa,hl+:#f38a8a" \
            --preview='bat --style=numbers --color=always {}'
    )

    [[ -n "$FILE_PATH" ]] || exit 0
fi

# ------------------------------------------------------------
# Validate
# ------------------------------------------------------------

[[ -f "$FILE_PATH" ]] || error "File does not exist: $FILE_PATH"
[[ -r "$FILE_PATH" ]] || error "File is not readable: $FILE_PATH"

# ------------------------------------------------------------
# File information
# ------------------------------------------------------------

FILE_NAME="$(basename "$FILE_PATH")"

FILE_BYTES=$(stat -c%s "$FILE_PATH" 2>/dev/null || stat -f%z "$FILE_PATH")

if command -v numfmt &>/dev/null; then
    FILE_SIZE=$(numfmt --to=iec --suffix=B "$FILE_BYTES")
else
    FILE_SIZE=$(du -h "$FILE_PATH" | cut -f1)
fi

FILE_TYPE=$(file -b "$FILE_PATH" 2>/dev/null | cut -d',' -f1)

# Keep type short enough for the terminal
if (( ${#FILE_TYPE} > 34 )); then
    FILE_TYPE="${FILE_TYPE:0:31}..."
fi

# ------------------------------------------------------------
# Temporary files
# ------------------------------------------------------------

TMP_RESPONSE=$(mktemp)
TMP_PROGRESS=$(mktemp)

# ------------------------------------------------------------
# Header
# ------------------------------------------------------------

clear

gum style \
    --foreground "$BLUE" \
    --border double \
    --border-foreground "$BLUE" \
    --align center \
    --width 58 \
    --padding "0 1" \
    "  HASTEBIN"

echo

gum style \
    --foreground "$TEXT" \
    --border rounded \
    --border-foreground "$DIM" \
    --padding "0 1" \
    "  $FILE_NAME  •  $FILE_SIZE  •  $FILE_TYPE"

echo

# ------------------------------------------------------------
# Upload
# ------------------------------------------------------------

printf '  '
gum style \
    --foreground "$CYAN" \
    --padding "0 0" \
    "󰑓 Uploading..."

echo

# Start upload
curl \
    -fS \
    --progress-bar \
    -X POST \
    -H "Content-Type: text/plain" \
    --data-binary @"$FILE_PATH" \
    "$UPLOAD_URL" \
    >"$TMP_RESPONSE" \
    2>"$TMP_PROGRESS" &

CURL_PID=$!

LAST_PERCENT=-1

# ------------------------------------------------------------
# In-place progress bar
# ------------------------------------------------------------

while kill -0 "$CURL_PID" 2>/dev/null; do

    CURRENT_PERCENT=$(
        tr '\r' '\n' < "$TMP_PROGRESS" 2>/dev/null |
        grep -oE '[0-9]{1,3}(\.[0-9]+)?%' |
        tail -1 |
        tr -d '%' |
        cut -d. -f1
    )

    [[ -n "$CURRENT_PERCENT" ]] || CURRENT_PERCENT=0

    (( CURRENT_PERCENT > 100 )) && CURRENT_PERCENT=100
    (( CURRENT_PERCENT < 0 )) && CURRENT_PERCENT=0

    BAR_WIDTH=38

    FILLED=$(( CURRENT_PERCENT * BAR_WIDTH / 100 ))
    EMPTY=$(( BAR_WIDTH - FILLED ))

    FILLED_BAR=$(printf '%*s' "$FILLED" '' | tr ' ' '━')
    EMPTY_BAR=$(printf '%*s' "$EMPTY" '' | tr ' ' '─')

    # Move to beginning of line and erase it.
    printf '\r\033[2K'

    printf '  \033[38;2;166;227;161m%s\033[0m \033[38;2;108;112;134m%s\033[0m \033[38;2;205;214;244m%3d%%\033[0m' \
        "$FILLED_BAR" \
        "$EMPTY_BAR" \
        "$CURRENT_PERCENT"

    LAST_PERCENT="$CURRENT_PERCENT"

    sleep 0.08
done

wait "$CURL_PID"
CURL_STATUS=$?

# Finish progress line
printf '\r\033[2K'

if [[ "$CURL_STATUS" -ne 0 ]]; then
    error "Upload failed."
fi

# ------------------------------------------------------------
# Parse response
# ------------------------------------------------------------

HASTE_KEY=$(jq -r '.key // empty' "$TMP_RESPONSE" 2>/dev/null)

[[ -n "$HASTE_KEY" ]] || error "Invalid response from server."

URL="$BASE_URL/$HASTE_KEY"

# ------------------------------------------------------------
# Copy URL
# ------------------------------------------------------------

COPIED=false

if command -v wl-copy &>/dev/null; then
    printf '%s' "$URL" | wl-copy
    COPIED=true

elif command -v xclip &>/dev/null; then
    printf '%s' "$URL" | xclip -selection clipboard
    COPIED=true

elif command -v xsel &>/dev/null; then
    printf '%s' "$URL" | xsel --clipboard --input
    COPIED=true

elif command -v pbcopy &>/dev/null; then
    printf '%s' "$URL" | pbcopy
    COPIED=true
fi

# ------------------------------------------------------------
# QR code
# ------------------------------------------------------------

QR=""

if command -v qrencode &>/dev/null; then
    QR=$(
        qrencode \
            -t ANSIUTF8 \
            -m 0 \
            "$URL"
    )
fi

# ------------------------------------------------------------
# Final panel
# ------------------------------------------------------------

echo

if [[ -n "$QR" ]]; then

    gum style \
        --border double \
        --border-foreground "$GREEN" \
        --padding "0 1" \
        --align center \
        --width 58 \
        "✓  UPLOAD COMPLETE" \
        "" \
        "  $FILE_NAME  •  $FILE_SIZE" \
        "" \
        "$URL" \
        "" \
        "$QR"

else

    gum style \
        --border double \
        --border-foreground "$GREEN" \
        --padding "0 2" \
        --align center \
        --width 58 \
        "✓  UPLOAD COMPLETE" \
        "" \
        "  $FILE_NAME  •  $FILE_SIZE" \
        "" \
        "$URL"

fi

# ------------------------------------------------------------
# Clipboard status
# ------------------------------------------------------------

echo

if [[ "$COPIED" == true ]]; then
    gum style \
        --foreground "$GREEN" \
        --align center \
        --width 58 \
        "󰆏  URL copied to clipboard"
else
    gum style \
        --foreground "$YELLOW" \
        --align center \
        --width 58 \
        "⚠  Clipboard utility not found"
fi

echo

