#!/bin/bash
set -euo pipefail

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
TEMP_DIR=$(mktemp -d)
trap 'rm -rf "${TEMP_DIR}"' EXIT


function die() {
    echo "FATAL:"
    echo "$@"
    exit 1
}

function get_getpkg() {
    # get getpkg
    export GETPKG="${SCRIPT_DIR}/../getpkg/output/getpkg"
    if [ ! -f "${GETPKG}" ]; then
        ARCH=$(uname -m)
        curl -L -s -o "${TEMP_DIR}/getpkg" "https://getbin.xyz/getpkg:latest-${ARCH}" || die "Failed to download getpkg"
        chmod +x "${TEMP_DIR}/getpkg"
        GETPKG="${TEMP_DIR}/getpkg"
        [ -f "${GETPKG}" ] || die "Failed to download getpkg"
    fi
}

function show_help() {
    cat << EOF

    sos is a script to upload files to a simple object storage server.

Usage: 
          sos upload <server> <file> <label:tag> [label:tag ...]

Example: 
          sos upload getbin.xyz ./file.txt file:latest 

This will upload the file to the server, and return the download URL.

Environment variables:
          SOS_WRITE_TOKEN: The write token to use for the upload. If not set, 
          the script will look in $HOME/.config/sos/write_token.txt.

EOF
    exit 0
}


function datetime() {
    date -u +"%Y.%m%d.%H%M"
}

function upload() {
    if [ "$#" -lt 3 ]; then
        echo "Usage: sos upload <server> <file> <label:tag> [label:tag ...]"
        exit 1
    fi

    server=$1
    file=$2
    first_label=$3
    LABELTAGS=("$first_label")
    [[ "$first_label" =~ : ]] || die "Label $first_label does not contain a tag!"

    shift 3
    for label in "$@"; do
        [[ "$label" =~ : ]] || die "Label $label does not contain a tag!"
        LABELTAGS+=("$label")
    done

    # check if file contains :
    [[ ! "$file" =~ : ]] || die "File contains : - this is not allowed!"
    [ -f "$file" ] || die "File not found: $file"


    # upload the file
    TARGET_SERVER="https://$server"
    echo "Uploading $file to $TARGET_SERVER"

    DATETIME=$(datetime)

    # deduplicate the labeltags
    mapfile -t LABELTAGS < <(printf "%s\n" "${LABELTAGS[@]}" | sort -u)
    LABELTAGS_JSON=$(printf '"%s",' "${LABELTAGS[@]}")
    LABELTAGS_JSON="[${LABELTAGS_JSON%,}]"

    # trip whitespace from the file path
    LOCALHASH=$("${GETPKG}" hash "${file}" | tr -d '[:space:]')
    echo "Local hash: $LOCALHASH"


METADATA_JSON=$(cat <<EOF
{
  "labeltags": $LABELTAGS_JSON,
  "description": "Uploaded by sos",
  "version": "$DATETIME"
}
EOF
)
    if [ -n "${SOS_WRITE_TOKEN:-}" ]; then
        WRITE_TOKEN="$SOS_WRITE_TOKEN"
    else
        TOKENPATH="$HOME/.config/sos/write_token.txt"
        if [ ! -f "$TOKENPATH" ]; then
            die "Token file not found in environment variable SOS_WRITE_TOKEN or $TOKENPATH. Please create it and put your write token in it."
        fi
        WRITE_TOKEN=$(cat "$TOKENPATH")
    fi


    EXISTSJSON=$(eval "curl -s \"https://$server/exists/$LOCALHASH\"") || die "Failed to check if file exists"
    DOESEXIT=$(echo "$EXISTSJSON" | jq -r '.exists')

    HASH=""

    if [ "$DOESEXIT" == "true" ]; then
        echo "File already exists, skipping upload"
        # UPDATE the metadata - this approach recommended by SWE-1 so we're not using form data...
        # curl -X PUT \
        #     -H "Authorization: Bearer ${WRITE_TOKEN}" \
        #     -H "Content-Type: application/json" \
        #     -d "{\"hash\":\"${LOCALHASH}\", \"metadata\":${METADATA_JSON}}" \
        #     "$TARGET_SERVER/update" \
        #     || die "Failed to update metadata at $TARGET_SERVER/update"

        curl -X PUT -H "Authorization: Bearer ${WRITE_TOKEN}" \
            -F "metadata=${METADATA_JSON}" \
            -F "hash=${LOCALHASH}" \
            "$TARGET_SERVER/update" \
            || die "Failed to upload $file to $TARGET_SERVER/update"
    else
        # UPLOAD the file + metadata
        curl -X PUT -H "Authorization: Bearer ${WRITE_TOKEN}" \
            -F "metadata=${METADATA_JSON}" \
            -F "file=@${file}" \
            "$TARGET_SERVER/upload" \
            || die "Failed to upload $file to $TARGET_SERVER/upload"
    fi

    echo " "
    echo " "

    JSON1=$(eval "curl -s \"https://$server/hash/$first_label\"")
    HASH=$(echo "$JSON1" | jq -r '.hash')

    JSON2=$(eval "curl -s \"https://$server/meta/$HASH\"") || die "Failed to get meta for $HASH"
    FILENAME=$(echo "$JSON2" | jq -r '.metadata.filename')

    echo "Metadata:"
    echo "$JSON2" | jq

    echo " "

    echo "Download URL: https://$server/$first_label > $FILENAME"
    echo "Alternative:  https://$server/$HASH > $FILENAME"
}

# if no arguments, show help
[ "$#" -gt 0 ] || show_help

CMD="$1"
shift

get_getpkg

if [ "$CMD" == "upload" ]; then
    upload "$@"
    exit $?
fi

die "Unknown command: $CMD"
