##########################
# user-defined functions #
##########################

########
# misc #
########
hex_to_string() {
	for hex in $(printf '%s' "$1" | sed 's/../&\n/g'); do
		[ "$hex" = "00" ] && continue
		printf "\x$hex"
	done
	unset hex
}

megamind() {
	len=$(printf '%s' "$*" | wc -c)
	printf "———————————%s———————————
⠀⣞⢽⢪⢣⢣⢣⢫⡺⡵⣝⡮⣗⢷⢽⢽⢽⣮⡷⡽⣜⣜⢮⢺⣜⢷⢽⢝⡽⣝
⠸⡸⠜⠕⠕⠁⢁⢇⢏⢽⢺⣪⡳⡝⣎⣏⢯⢞⡿⣟⣷⣳⢯⡷⣽⢽⢯⣳⣫⠇
⠀⠀⢀⢀⢄⢬⢪⡪⡎⣆⡈⠚⠜⠕⠇⠗⠝⢕⢯⢫⣞⣯⣿⣻⡽⣏⢗⣗⠏⠀
⠀⠪⡪⡪⣪⢪⢺⢸⢢⢓⢆⢤⢀⠀⠀⠀⠀⠈⢊⢞⡾⣿⡯⣏⢮⠷⠁⠀⠀
⠀⠀⠀⠈⠊⠆⡃⠕⢕⢇⢇⢇⢇⢇⢏⢎⢎⢆⢄⠀⢑⣽⣿⢝⠲⠉⠀⠀⠀⠀
⠀⠀⠀⠀⠀⡿⠂⠠⠀⡇⢇⠕⢈⣀⠀⠁⠡⠣⡣⡫⣂⣿⠯⢪⠰⠂⠀⠀⠀⠀
⠀⠀⠀⠀⡦⡙⡂⢀⢤⢣⠣⡈⣾⡃⠠⠄⠀⡄⢱⣌⣶⢏⢊⠂⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢝⡲⣜⡮⡏⢎⢌⢂⠙⠢⠐⢀⢘⢵⣽⣿⡿⠁⠁⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠨⣺⡺⡕⡕⡱⡑⡆⡕⡅⡕⡜⡼⢽⡻⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣼⣳⣫⣾⣵⣗⡵⡱⡡⢣⢑⢕⢜⢕⡝⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⣴⣿⣾⣿⣿⣿⡿⡽⡑⢌⠪⡢⡣⣣⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⡟⡾⣿⢿⢿⢵⣽⣾⣼⣘⢸⢸⣞⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠁⠇⠡⠩⡫⢿⣝⡻⡮⣒⢽⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
——————————————————————" "$*"
	for i in $(seq $len); do
		printf '—'
	done
	printf '\n'
	unset len
}

b64() {
	# base64 wrapper , also converts url base64
	printf "%s" "$1" | tr "._-" '=/+' | base64 -w 0 $2
}

deploy() {
	source ./.env
	ext="yml"
	docker_compose_file="docker-compose"
	[ "$APP_ENV" = "dev" ] && docker_compose_file="docker-compose-dev"
	[ -f "$docker_compose_file.$ext" ] || ext="yaml"
	[ ! -f "$docker_compose_file.$ext" ] && printf "Docker compose file not found." && return 1
	systemctl is-active docker.socket || systemctl start docker.socket
	docker compose -f "$docker_compose_file.$ext" "$@"
	docker compose -f "$docker_compose_file.$ext" down
}

clshist() {
	[ -z "$ZED_TERM" ] || return 0
	tmpfile="$(mktemp)"

	# keep recent entries at bottom
	tac "$HISTFILE" | awk '!seen[$0]++' | tac | tee "$tmpfile" >/dev/null

	# Trim to HISTSIZE (default:1000)
	total_lines=$(wc -l <"$tmpfile")
	if [ "$total_lines" -gt "${HISTSIZE:-1000}" ]; then
		sed -i "1,$((total_lines - HISTSIZE))d" "$tmpfile"
	fi

	# Replace original file
	[ -f "$tmpfile" ] && mv "$tmpfile" "$HISTFILE"
	unset tmpfile total_lines
}

v() {
	[ -z "$*" ] && nvim -O $(fzf --preview 'bat --color=always --style=numbers --line-range=:500 {}' -m | tr '\n' ' ') || nvim -O $*
}

help() {
	"$@" --help 2>&1 | bat --plain --language=help
}

#########################
# Git Related Functions #
#########################
gtp() {
	cache_file="${XDG_CACHE_HOME:-$HOME/.cache}/.commit_messages"
	curl -sL "https://raw.githubusercontent.com/ngerakines/commitment/master/commit_messages.txt" --etag-compare "$cache_file.etag" --etag-save "$cache_file.etag" -o "$cache_file"
	[ -z "$*" ] && commit=$(shuf -n1 "$cache_file") || commit=$*
	git add -p
	printf "\nCommit Message: $commit\n"
	git commit -m "$commit"
	git push
	unset commit
}

gtb() {
	[ -z "$*" ] && br=$(git branch -a | fzf --border=rounded --layout=reverse --height=10 | tr -d ' ') || br=$*
	[ -z "$br" ] || git switch $br
	unset br
}

gtd() {
	preview="git diff $@ --color=always -- {-1}"
	file=$(git diff $@ --name-only --relative | fzf --ansi --preview $preview --preview-window right:65%:wrap -0)
	[ -n "$file" ] && nvim $file
	unset preview file
}

gtc() {
	[ -z "$1" ] && [ -p "/dev/stdin" ] && read -r query </dev/stdin || query=$1
	git clone "$query"
}

gtr() {
	source "$HOME"/.config/.env
	github_creds #load creds
	[ -z "$1" ] && [ -p "/dev/stdin" ] && read -r query </dev/stdin || query=$1
	curl -s "https://api.github.com/users/$query/repos" -H "Authorization: Bearer $GH_TOKEN" | sed -nE 's|.*ssh_url": "([^"]*)".*|\1|p' | fzf --border --height=10 --layout=reverse -0
	github_creds unload
}

gtu() {
	source "$HOME"/.config/.env
	github_creds #load creds
	[ -z "$1" ] || curl -s "https://api.github.com/search/users?q=$1" -H "Authorization: Bearer $GH_TOKEN" | sed -nE 's_.*login": "([^"]*)".*_\1_p' | fzf --layout=reverse --border --height=10 -0
	github_creds unload
}

##################################
# Using Android as Second Screen #
##################################
headless_add() {
	set -x

	#check for android devices, and select which one u wanna work upon
	device=$(adb devices | sed '/^\*/d;/^List of devices/d;/^$/d' | cut -f1 | fzf -1)

	#throw issue if no android has been there
	[ -z "$device" ] && printf "Unable to detect Android using ADB" && return 1

	#select device resolution and fps
	RES=$(adb -s "$device" shell dumpsys display | sed -nE 's|^[[:space:]]*DisplayModeRecord.*width=([0-9]*), height=([0-9]*), fps=([0-9\.]*).*|\2x\1@\3|p' | fzf --prompt="Select Resolution > " -1)

	#device fps for wayvnc
	device_fps=$(printf '%s' "$RES" | cut -d'@' -f2)
	position=$(printf 'auto\nauto-left' | fzf --prompt="Which position? >")

	headless="HEADLESS-ANDROID-$device"

	#create, if not exists
	if ! hyprctl monitors | grep -q "$headless"; then
		hyprctl output create headless "$headless" | grep -q 'ok' && printf '\n\nCreate Headless Display: %s' "$headless"
	fi

	#there is issue
	[ -z "$headless" ] && printf "Something went wrong\n" && return 1

	# set resolution,fps, and scaling
	hyprctl keyword monitor $headless,$RES,$position,'1'

	#define ur preferred port
	for PORT in {11000..11100}; do
		! ss -tln | grep -q ":$PORT" && break
	done

	# kill existing wayvnc and start a new one
	#pgrep -af "wayvnc" && killall wayvnc
	setsid -f wayvnc --gpu --output="$headless" --disable-input --socket="/tmp/$headless" --max-fps="$((device_fps * 2))" 0.0.0.0 $PORT

	#reverse port forward to device, and start VNC
	adb -s "$device" reverse tcp:$PORT tcp:$PORT
	adb -s "$device" shell am start --user 0 -a android.intent.action.VIEW -d "vnc://127.0.0.1:$PORT"

	#cleanup
	unset PORT headless RES
	hyprctl dispatch moveworkspacetomonitor 2 1
	set +x
}

headless_rm() {
	set -x
	headless=$(hyprctl monitors | sed -nE 's|.*(HEADLESS-ANDROID-[^ ]*).*|\1|p' | fzf --prompt="Select Which Device to Remove >" -0 -1)
	[ -n "$headless" ] && hyprctl output remove $headless
	pid=$(pgrep "wayvnc --gpu --output=$headless" | cut -d' ' -f1)
	kill -9 $pid
	unset headless
	set +x
}

###################################
# Cookies Extraction from browser #
###################################
get_cookies() {
	# the user has firefox installed
	logdir="/tmp"
	if [ ! -f "$HOME/.config/google-chrome/Default/Cookies" ]; then
		cp "$(find "$HOME/.mozilla" -type f -iname 'cookies.sqlite' | head -1)" "$logdir/cookies.sqlite"
		sqlite3 "$logdir/cookies.sqlite" "SELECT name, value FROM moz_cookies WHERE host='$1';" | tr '|\n' '=;'
		rm "$logdir/cookies.sqlite"
		return 0
	fi
	for i in $(sqlite3 "$HOME/.config/google-chrome/Default/Cookies" "SELECT name,REPLACE(base64(SUBSTR(encrypted_value,4)),CHAR(10),'') FROM cookies WHERE host_key='$1';"); do
		printf "%s=%s; " "$(printf '%s' "$i" | cut -d'|' -f1)" "$(printf '%s' "$i" | cut -d'|' -f2 | base64 -d | openssl enc -d -aes-128-cbc -K fd621fe5a2b402539dfa147ca9272778 -iv 20202020202020202020202020202020 | cut -c33-)"
	done
}

#############################################
# Downloading | Streaming Related Functions #
#############################################
mkvcinemas() {
	local base_url="https://mkvcinemas.ist"
	local agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

	[ -z "$*" ] && printf "Search> " && read -r query || query="$*"

	local movie=$(curl -s "$base_url/wp-admin/admin-ajax.php" -X POST -d "s=$query&action=searchwp_live_search&swpengine=default&swpquery=$query" -e "$base_url" -H "X-Requested-With:XMLHttpRequest" -L -A "$agent" | sed -nE 's|.*url\(([^\)]*).*href=".*/([^"]*)/".*|\1\t\2|p' | fzf -0 --preview="img2sixel {1} -w 280" --with-nth 2.. --layout=reverse --height=20 --border --preview-window right:36%:wrap | cut -f2)

	[ -z "$movie" ] && printf "No Movie Found/Selected." && return 1

	local url=$(curl -s "$base_url/$movie" -e "$base_url" -LA "$agent" | sed 's|<span>|\n|g' | sed -nE 's|.*title="([^"]*)" href="([^"]*)" target.*[>|;](.*)</a><.*|\2`[\3] \1|p;' | fzf -0 -d'`' --with-nth 2.. --layout=reverse --height=20 --border | cut -d'`' -f1)
	[ -z "$url" ] && printf "No Url Selected" && return 1
	xdg-open "$url"
}

gdown() {
	agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/13$(head /dev/urandom | tr -dc '6-8' | cut -c1).0.0.0 Safari/537.36"
	uuid=$(curl -sL "$1" -A "$agent" | sed -nE 's|.*name="(uuid)" value="([^"]*)".*|\1=\2|p')
	aria2c -x16 -s16 "$1&confirm=t&$uuid" -U "$agent" --summary-interval=0 -d "${2:-.}"
}

mpv_jellyfin() {
	url=${1:-$(wl-paste)}
	uuid=$(printf '%s' "$url" | sed -nE 's|.*/Items/([^/]*)/Download.*|\1|p')
	key=$(printf '%s' "$url" | sed -nE 's|.*api_key=([^&]*)|\1|p')
	formatted_uuid=$(printf '%s' "$uuid" | sed -E 's/(.{8})(.{4})(.{4})(.{4})(.{12})/\1-\2-\3-\4-\5/')
	subtitle="$(printf '%s' "$url" | sed -nE 's|(.*)/Items/.*|\1|p')/Videos/$formatted_uuid/$uuid/Subtitles/0/0/Stream.ass?api_key=$key"

	if ! curl -s "$subtitle" | grep -q "Error processing request."; then
		sub_arg="--sub-file=$subtitle"
	fi

	setsid -f mpv "$url" $sub_arg
	unset subtitle sub_arg uuid formatted_uuid key
}

####################################################
# Notification API, Sends Notification to my phone #
####################################################
ntfy() {
	source $HOME/.config/.env

	ntfy_creds #load
	curl -s "$NTFY_URL/$NTFY_TOPIC" -d "$1" -H "Authorization: Bearer $NTFY_TOKEN" -H "Title: $2"
	ntfy_creds "unload" #unload
}

############################################
# Functions for uploading file for sharing #
############################################
url_oshi() {
	days=${2:-1}
	out=$(curl -k https://oshi.at -F shorturl=0 -F "f=@$1" -F "expire=$((days * 1440))") #1440 means 1 day duration
	[ -z "$out" ] && return 1
	printf "%s" "$out" | sed -nE 's|DL: (.*)|\1|p' | wl-copy && notify-send "Link copied to clipboard"
	wl-paste
	curr=$(date '+%s')
	#storing only long duration links
	[ -z "$2" ] && printf "%s\n%s" "$out" "$((curr + (86400 * days)))" | tr '\n' '>' | sed 's/>/ | /g' >>$HOME/.cache/oshi-urls

	#deleting file uploaded than nth day ago
	for i in $(cut -d'|' -f3 $HOME/.cache/oshi-urls | tr -d ' '); do
		[ "$curr" -ge "$i" ] && sed -i "/$i/d" $HOME/.cache/oshi-urls &
	done
	echo >>$HOME/.cache/oshi-urls
}

url_nextcloud() {
	[ ! -f "$HOME/.config/.env" ] && notify-send "Credentials not found" -u critical && return 1
	source "$HOME"/.config/.env
	nextcloud_creds #load creds

	cloudname="$(basename "$1")"
	curl -u "$NC_USER:$NC_TOKEN" -s "$NC_URL/remote.php/dav/files/${NC_USER}${NC_SHARE_PATH}/$cloudname" -T "$tmp_file" || return 1

	#To enable sharing, the output will be in json containing share link
	curl -u "$NC_USER:$NC_TOKEN" -s "$NC_URL/ocs/v2.php/apps/files_sharing/api/v1/shares" -H 'content-type: application/json' -H 'accept: application/json, text/plain, */*' -H 'OCS-APIRequest: true' --data-raw '{"path":"'"${NC_SHARE_PATH}/$cloudname"'","shareType":3,"expireDate":"'"$expire_date"'"}' | sed -nE 's|.*"url":"([^"]*)".*|\1|p' | sed 's/\\//g' | wl-copy && info "com.github.davidmhewitt.clipped" "2000" "Share Link Created and copied to clipboard"
	nextcloud_creds "unload"
}

##############################################
# Package Management Wrapper for Paru|Pacman #
##############################################
addpkg() {
	[ -z "$*" ] && printf "\033[1;31mPlease write the name of package (just some words)..\033[0m" && return 1
	packages=$(paru -Ss "$*" | sed -nE 's|^([a-zA-Z]*)/([^ ]*).*|[\1] \2|p' | fzf --layout=reverse --border --preview 'paru -Si $(echo {} | cut -d" " -f2) | bat --language=yaml --color=always -pp' --preview-window right:65%:wrap -m | cut -d' ' -f2- | tr '\n' ' ' | tr -d "'")
	[ -z "$packages" ] && printf "\033[1;31mNo package selected..\033[0m" && return 1
	paru -S $(printf "%s" "$packages")
}

rmpkg() {
	packages=$(paru -Qq | fzf --preview 'paru -Si {} | bat --language=yaml --color=always -pp' --preview-window right:65%:wrap -m | tr '\n' ' ')
	[ -z "$packages" ] && printf "\033[1;31mNo package selected..\033[0m" && return 1
	paru -Rcns $(printf "%s" "$packages")
}

####################
# Open VPN Wrapper #
####################
vpn() {
	query="${1:-stop}"
	[ "$query" = "up" ] && query="start"
	# check and stop if tailscale is running
	[ "$query" = "start" ] && ! tailscale status | grep -qi 'tailscale is stopped' && doas tailscale down
	doas systemctl $query openvpn-client@vpn.service && printf "Openvpn %sed" "$query"
}

# vim: ft=zsh
