#!/usr/bin/env bash

thisFile=$(realpath "$0")
DOTFILES="${DOTFILES:-$HOME/dotfiles}"
BOOKMARKS_FILE="${DOTFILES}/secrets/wb.txt"

# Decrypt bookmarks from sops
getBookmarks() {
    if [[ -f ${BOOKMARKS_FILE} ]]; then
        # Unencrypted file (for development/testing)
        cat "${BOOKMARKS_FILE}"
    elif [[ -f "${BOOKMARKS_FILE%.txt}.enc" ]]; then
        # Encrypted file
        sops --decrypt --input-type binary "${BOOKMARKS_FILE%.txt}.enc" 2>/dev/null
    else
        echo "Error: No bookmarks file found" >&2
        exit 1
    fi
}

# Defaults
isCopy=0
editMode=0
q=""
noFuzzy=0
queryMode=0

if ! type fzf >/dev/null 2>&1; then
    noFuzzy=1
fi

cleanup() {
    rm -f /tmp/.wb
    clear-pbcopy 60 &
}

trap cleanup EXIT

bks() {
    getBookmarks | awk '!/^[[:space:]]*#/ && !/^[[:space:]]*$/ {print $1}'
}

execute() {
    # --------------------------------------------------------------------
    # If key == $q, then it's a match, then we do the following:
    #    a. Copy the "url" to the clipboard (with "pbcopy" in Mac or
    #        "clip" in Linux).  How do we know it's a Mac, we just simply
    #        check if there's a ~/Music folder in your homedir.  If
    #        there is, it's likely a Mac, else it's Linux.
    #    b. I have a "clear-pbcopy" script that basically clears the
    #        clipboard after 20 seconds (for security reason) because
    #        you don't want to accidentally copy-paste your personal
    #        links in your email or your chat applications.  It is as simple as
    #        a oneline command:
    #        "sleep 20; echo "nothing-here" | pbcopy"
    #    c. If the first argument is "-c" then we mean we just want to
    #        copy the string to the clipboard, so we just continue
    #    d. Then we see if the "url" contains "http" or "www", if so
    #        we open it with ~/bin/browser.  You must have your own
    #        "browser" script that opens your favorite web browser, e.g.
    #        in Mac, my "~/bin/browser" contains:
    #          open -a /Applications/Firefox.app $*
    #        However, if the "url" does not contain http/www,
    #           e.g. the key and url line is like this:
    #             mytodofile ~/Documents/mytodofile.txt
    #        then I open it "open" command line provided by Mac
    #    d. We are done (exiting)
    # --------------------------------------------------------------------

    echo ""

    # ---------------------- a
    echo "  copying $url"
    echo "$url" | cb

    # ---------------------- b
    if type clear-pbcopy >/dev/null 2>&1; then
        clear-pbcopy 60 &
    fi

    # ---------------------- c
    if [ $isCopy == 1 ]; then
        echo "  Copied to clipboard"
        echo ""
        exit
    fi

    # ---------------------- d
    echo "  open $url"
    x-open $url

    # ---------------------- d
    echo ""
    exit
}

fuzzy() {
    # Use awk to parse bookmarks in a single pass (much faster than bash loop)
    formatted=$(getBookmarks | awk '
        # Skip decorative headers and section dividers
        /^#[-=~# ]*$/ || /^# *--/ || /^##+/ { next }

        # Accumulate description and extract tags from comments
        /^#[^#]/ {
            sub(/^# */, "")
            desc = desc (desc ? " " : "") $0
            # Extract @tags
            n = split($0, words, " ")
            for (i = 1; i <= n; i++) {
                if (words[i] ~ /^@/) {
                    tags = tags (tags ? " " : "") words[i]
                }
            }
            next
        }

        # Handle bookmark lines (non-comment, non-empty)
        /^[^#[:space:]]/ {
            key = $1
            # Skip @-prefixed keys
            if (key ~ /^@/) { desc = ""; tags = ""; next }

            # Get URL (everything after first field)
            url = $0
            sub(/^[^ \t]+[ \t]+/, "", url)

            # Clean description
            gsub(/\n/, " ", desc)
            if (desc == "") desc = "-"
            if (tags == "") tags = "-"

            print key "\t" url "\t" desc "\t" tags

            desc = ""
            tags = ""
        }
    ')

    selected_line=$(echo "$formatted" |
        fzf -i --with-nth=1 \
            --delimiter=$'\t' \
            --query="$q" \
            --prompt="🔍 Select bookmark: " \
            --preview='bash -c "url=\$(echo {} | cut -f2); desc=\$(echo {} | cut -f3); tags=\$(echo {} | cut -f4); echo -e \"\$url\n\nDesc: \$desc\n\nTags: \$tags\""' \
            --preview-window=down:12:wrap)

    if [[ -n $selected_line ]]; then
        IFS=$'\t' read -r key url _ <<<"$selected_line"
        execute "$url"
    else
        echo "  No selection made"
        echo ""
    fi
}

help() {
    echo ""
    echo "Usage: wb [-c] [-e] <key> [key2] [key3] ..."
    echo ""
    echo "Options:"
    echo "  -c         Copy to clipboard without opening"
    echo "  -e         Edit the bookmarks file"
    echo "  -nf        No Fuzzy Match"
    echo "  -h         Show help"
    echo ""
    echo "Examples:"
    echo "  wb cnn          # Open the cnn bookmark"
    echo "  wb -c gmail     # Copy Gmail URL without opening"
    echo "  wb 230 zoom     # Open bookmark matching '230.*zoom'"
    echo "  wb ai sci zoom  # Open bookmark matching 'ai.*sci.*zoom'"
    echo ""
}

# --------------------------------------------------------------------
# [ 70-char wide ]
# 34567890123456789012345678901234567890123456789012345678901234567890
#        1         2         3         4         5         6         7
# --------------------------------------------------------------------

# --------------------------------------------------------------------
# 0. Setup $thisFile and
#    if "wb" is called with no arguments, then
#    just open this "wb" file with "e" --> emacs
#    You can change "e" to "vi" or other text editor
# --------------------------------------------------------------------

# Parse arguments
args=()
while [ $# -gt 0 ]; do
    case "$1" in
    -c)
        isCopy=1
        ;;
    -e)
        editMode=1
        ;;
    -h | --help)
        help
        exit 0
        ;;
    -nf)
        noFuzzy=1
        ;;
    -q)
        queryMode=1
        ;;
    -*)
        echo "Unknown option: $1"
        exit 1
        ;;
    *)
        args+=("$1")
        ;;
    esac
    shift
done

# Build pattern from multiple arguments (e.g., "wb 230 si te" -> "230.*si.*te")
if [ ${#args[@]} -gt 0 ]; then
    q="${args[0]}"
    for ((i = 1; i < ${#args[@]}; i++)); do
        q="$q.*${args[$i]}"
    done
fi

if [[ $editMode == 1 ]]; then
    encFile="${BOOKMARKS_FILE%.txt}.enc"
    if [[ -f $encFile ]]; then
        echo "Editing encrypted bookmarks file"
        # Decrypt to the .txt file (matches .sops.yaml path_regex), edit, re-encrypt
        trap "rm -f '${BOOKMARKS_FILE}'" EXIT
        sops --decrypt --input-type binary --output-type binary "$encFile" >"${BOOKMARKS_FILE}"
        ${EDITOR:-vim} "${BOOKMARKS_FILE}"
        sops --encrypt --input-type binary --output-type binary "${BOOKMARKS_FILE}" >"$encFile"
        rm -f "${BOOKMARKS_FILE}"
        echo "Saved and re-encrypted"
    elif [[ -f ${BOOKMARKS_FILE} ]]; then
        echo "Editing ${BOOKMARKS_FILE}"
        ${EDITOR:-vim} "${BOOKMARKS_FILE}"
    else
        echo "Error: No bookmarks file found"
        exit 1
    fi
    exit
fi

if [[ $queryMode == 1 ]]; then
    if [[ -z $q ]]; then
        bs=$(bks)
    else
        bs=$(bks | grep -i "$q")
    fi
    num=$(echo "$bs" | wc -l | tr -d ' ')
    bs=$(echo "$bs" | tr '\n' ',' | sed 's/,$//' | sed 's/,/, /g')
    echo "$num bookmarks: ($bs)"
    exit
fi

if [[ $q == "" ]]; then
    if [[ $noFuzzy == 1 ]]; then
        help
    else
        fuzzy
    fi
    exit
fi

## --------------------------------------------------------------------
## 1. Find all bookmarks matching the pattern using regex
##    Store matches in /tmp/.wb (using awk for speed)
## --------------------------------------------------------------------
tempFile=/tmp/.wb
getBookmarks | awk -v pattern="$q" '
    !/^[[:space:]]*#/ && !/^[[:space:]]*$/ && $1 ~ pattern {print}
' >"$tempFile"
hitCount=$(wc -l <"$tempFile" | tr -d ' ')

## --------------------------------------------------------------------
## 2. Handle results based on hit count
## --------------------------------------------------------------------

# No hits found
if [ $hitCount -eq 0 ]; then
    echo ""
    if [[ $noFuzzy == 1 ]]; then
        echo "  '$q' not found"
        echo "  Available bookmarks matching pattern:"
        bks | grep -iE "$q" | cat -n
    else
        fuzzy
    fi
    echo ""
    exit
fi

# Multiple hits - check for exact match first
if [ $hitCount -gt 1 ]; then
    exactHit=0
    while read -r key url misc; do
        if [[ $key == "$q" ]]; then
            exactHit=1
            echo "$key $url" >"$tempFile"
            break
        fi
    done <"$tempFile"
    if [ $exactHit -eq 1 ]; then
        hitCount=1
    fi
fi

# Still multiple hits - show options or use fuzzy
if [ $hitCount -gt 1 ]; then
    if [[ $noFuzzy == 1 ]]; then
        echo ""
        echo "  Multiple matches for '$q':"
        sort "$tempFile" | while read -r key url misc; do
            echo "        $key"
        done
        echo ""
    else
        fuzzy
    fi
    exit
fi

# Single hit - execute
if [ $hitCount -eq 1 ]; then
    read -r key url _ <"$tempFile"
    execute "$url"
fi

## --------------------------------------------------------------------
## 5. Bookmarks are now stored in secrets/wb.txt (or secrets/wb.enc when encrypted)
##    To encrypt: sops --encrypt --input-type binary --output-type binary secrets/wb.txt > secrets/wb.enc
##    Then remove secrets/wb.txt
## --------------------------------------------------------------------
