#!/usr/bin/env bash
# set -vx

printhelp() {
    cat <<EOM
usage: dye [-x|-r] [color_code]
options:
 -x                  hex to rgb
 -r                  rgb to hex
examples:
 dye -x "#ffffff"
 dye -r 255 255 255
 dye -r "rgb(255, 255, 255)"
 dye -x "#43fF6480"
 dye -r 67 255 100 0.5
 dye -r "rgba(67, 255, 100, 0.5)"
EOM
    exit 0
}

error() {
    printf "error: %s\n" "$1" 1>&2
    exit 2
}

dependencycheck() {
    local dep missingdependencies=0
    for dep in "$@"; do
        if ! command -v "$dep" &>/dev/null; then
            error "dependency not met: $dep"
        fi
    done
    if [[ $missingdependencies -gt 0 ]]; then
        exit 1
    fi
}

hex_to_rgb() {
    local a
    # null command ':' removes all leading hashtag characters
    : "${1/\#/}"
    # if hex value is 8 characters
    if ((${#_} == 8)); then
        # convert characters to hex (see credits at bottom)
        ((r = 16#${_:0:2}, g = 16#${_:2:2}, b = 16#${_:4:2}, a = 16#${_:6:2}))
        # simple calc for alpha channel
        a=$(echo "scale=2; $a / 255" | bc)
    # else if hex value is 6 characters (no alpha channel)
    elif ((${#_} == 6)); then
        ((r = 16#${_:0:2}, g = 16#${_:2:2}, b = 16#${_:4:2}))
        a=1.0
    # else if hex value is 3 characters (minimal hex value provided)
    elif ((${#_} == 3)); then
        # if the first character still has a hashtag in it...
        if [[ ${1:0:1} != "#" ]]; then
            color="#$1"
        else
            color="$1"
        fi
        # grab out each passed value
        r="$(echo "$color" | cut -c2)"
        g="$(echo "$color" | cut -c3)"
        b="$(echo "$color" | cut -c4)"

        # and convert them to hexadecimal
        r=$(printf "%d" 0x$r$r)
        g=$(printf "%d" 0x$g$g)
        b=$(printf "%d" 0x$b$b)

        # ((r = 16#${_:0:1}, g = 16#${_:1:1}, b = 16#${_:2:1}))
        a=1.0
    else
        error "$1 is not a recognized hex color code."
    fi
    printf "%s\n" "rgba($r, $g, $b, $a)"
}

# parse_rgb() takes rgb string to pass to rgb_to_hex()
parse_rgb() {
    local regex='^rgb[a]?[(][0-9]{1,3}, [0-9]{1,3}, [0-9]{1,3}[)]$|^rgb[a]?[(][0-9]{1,3}, [0-9]{1,3}, [0-9]{1,3}, [0-1]?.[0-9][0-9]?[)]$'
    if [[ $2 =~ $regex ]]; then
        local numbers
        numbers=$(echo "$2" | sed -n 's/.*\(([^()]*)\).*/\1/p' | sed 's/[()]//g' | sed 's/,\s/ /g')
        read -r -a rgb <<< "$numbers"
        rgb_to_hex  "${rgb[$"0"]}" "${rgb[$"1"]}" "${rgb[$"2"]}" "${rgb[$"3"]}"
    else
        error "pattern passed is not valid rgba format" 2
    fi
}

rgb_to_hex() {
    local a
    # if a fourth arg is provided (alpha channel)
    if [[ -n "$4" ]]; then
        # converts alpha channel to hex (see below)
        a=$(printf "%02x\n" "$(echo "scale=0; $4*255" | bc)" 2>/dev/null)
        printf "#%02x%02x%02x%s\n" "$1" "$2" "$3" "$a"
    else
        printf "#%02x%02x%02x\n" "$1" "$2" "$3"
    fi
}

main() {
    [[ "$#" -lt 1 ]] && printhelp

    while getopts ":x:r:?" arg; do
        case $arg in
            x)
                if [[ "$#" -gt 2 ]]; then
                    error "-x only parses one following argument"
                fi
                local rgbval clipit
                rgbval=$(hex_to_rgb "${2:-''}")
                printf "%s\n" "$rgbval"
                read -e -r -p "save code to clipboard?(y/n): " clipit
                if [[ "$clipit" == "yes" || "$clipit" == "y" ]]; then
                    dependencycheck xclip
                    printf "%s" "$rgbval" | xclip -sel clip
                fi
                ;;
            r)
                local hexval clipit
                if [[ "$#" -eq 2 ]]; then
                    hexval=$(parse_rgb "$@")
                    printf "%s\n" "$hexval"
                    read -e -r -p "save code to clipboard?(y/n): " clipit
                    if [[ "$clipit" == "yes" || "$clipit" == "y" ]]; then
                        dependencycheck xclip
                        printf "%s" "$hexval" | xclip -sel clip
                    fi
                else
                    hexval=$(rgb_to_hex "${@:2}")
                    printf "%s\n" "$hexval"
                    read -e -r -p "save code to clipboard?(y/n): " clipit
                    if [[ "$clipit" == "yes" || "$clipit" == "y" ]]; then
                        dependencycheck xclip
                        printf "%s" "$hexval" | xclip -sel clip
                    fi
                fi
                ;;
            ?)
                printhelp
                ;;
        esac
    done
}

main "$@"

# Credits:
# Thanks go out to those who helped:

# Akash Mittal, whose article provided the original versions of hex_to_rgb() and rgb_to_hex() taken from
# https://akashmittal.com/code-example-convert-hex-color-to-rgb-rgb-to-hex-using-bash-script/

# redditor zeekar who broke down what those functions did line by line:
# https://reddit.com/r/bash/comments/zqmvz8/rgbhex_converter_syntax_how_does_this_work/

# redditor DyslexicHobo, who suggested ChatGPT, which I used to finalize the
# rgb_to_hex() function. Thank you AI overlords!
# https://openai.com/blog/chatgpt/
