#!/bin/bash
proj=aramis
tmp=/tmp/aramis-working
reqs="lddtree patchelf realpath dpkg dpkg-deb xargs awk git sed gcc tree tar sort head cut basename dirname"
count=$(echo $reqs | awk '{printf NF}')
iter=$((count+1))
while [ "$iter" != "$((count+1))" ]
do
	req=$(echo $reqs | cut -d " " -f $iter)
	if ! which $req 2>&1 1>/dev/null
	then
		echo "Dependency not found: $req"
		exit 1
	fi
	iter=$((iter+1))
done

if [ "$1" == "" ] || [ "$1" == "help" ] || [ "$1" == "--help" ]
then
	echo "Usage: $proj [init|import|export|mkdir|tree|clean|build]"
	echo "       $proj [install|uninstall|list]"
	exit 0
elif [ "$1" == "list" ]
then
	if [ ! -d /opt/aramis/* ]
	then
		echo "No packages installed."
	else
		find /opt/aramis/ -maxdepth 2 | sed 's/\/opt\/aramis\///' | grep '/' | sed 's/\//\t\t/'
	fi
	exit 0
elif [ "$1" == "install" ] || [ "$1" == "--install" ]
then
	set -e
	if [ "$(echo $2 | xargs)" == "" ]
	then
		echo "Usage: $proj [tar file]"
		exit 0
	fi
	file=$(tar -tf $2 2>/dev/null | awk '{print length($0) "\t" $0}' | sort -nr | head -1 | cut -f2-)
	if [ "$file" == "" ]
	then
		echo "Error: Could not read file."
		exit 1
	fi
	name=$(echo $file | cut -d "/" -f 3)
	vers=$(echo $file | cut -d "/" -f 4)
	if [ -d /opt/$proj/$name/$vers ]
	then
		echo "Error: Package already installed."
		exit 1
	fi
	others=$(ls /opt/$proj/$name/ 2>/dev/null | xargs)
	count=$(echo $others | awk '{printf NF}')
	if [ "$count" != "0" ]
	then
		echo "Warning: There exists other versions"
		iter=1
		while [ "$iter" != "$((count+1))" ]
		do
			ver=$(echo $others | cut -d " " -f $iter)
			echo -e "\t$name\t$ver"
			iter=$((iter+1))
		done
		read -p "Proceed anyway? " ans
		if [ "$ans" != "Y" ] && [ "$ans" != "y" ]
		then
			exit 0
		fi
	fi
	tar -xf $2 -C /
	tar -tf $2 | awk '{print length($0) "\t" $0}' | sort -nr | cut -f2- | xargs > /opt/$proj/$name/$vers/.list
	echo -e "Installed: $name $vers"
	exit 0
elif [ "$1" == "uninstall" ] || [ "$1" == "--uninstall" ] || [ "$1" == "remove" ] || [ "$1" == "--remove" ]
then
	set -e
	if [ "$(echo $2 | xargs)" == "" ]
	then
		echo "Usage: $proj [name]"
		echo "Usage: $proj [name] [version]"
		exit 0
	fi
	name=$2
	vers=$3
	if [ "$(echo $vers | xargs)" == "" ]
	then
		vers="*"
	fi
	if [ ! -d /opt/$proj/$name/$vers ]
	then
		echo "Error: Package is not installed."
		exit 1
	fi
	lists=$(ls /opt/$proj/$name/$vers/.list 2>/dev/null | xargs)
	count=$(echo "$lists" | awk '{printf NF}')
	iter=1
	while [ "$iter" != "$((count+1))" ]
	do
		list=$(echo $lists | cut -d " " -f $iter)
		files=$(cat $list)
		rm -rf 2>/dev/null $(dirname $list)
		count2=$(echo $files | awk '{printf NF}')
		iter2=1
		while [ "$iter2" != "$((count2+1))" ]
		do
			file=$(echo $files | cut -d " " -f $iter2)
			if [ "$file" != "" ]
			then
				set +e
				rm -d /$file 2>/dev/null
				set -e
			fi
			iter2=$((iter2+1))
		done
		iter=$((iter+1))
	done
	echo -e "Removed: $name $vers"
	exit 0
elif [ "$1" == "init" ] || [ "$1" == "--init" ]
then
	if [ "$2" == "" ] || [ "$2" == "help" ] || [ "$2" == "--help" ]
	then
		if [ "$(echo $3 | xargs)" == "" ]
		then
			echo "Usage: $proj new [name] [version]"
			exit 0
		else
			echo "Error: Invalid name."
			exit 1
		fi
	fi
	if [ "$(echo $2 | xargs)" == "" ]
	then
		echo "Error: Invalid name."
		exit 1
	fi
	if [ "$(echo $3 | xargs)" == "" ]
	then
		echo "Error: Invalid version."
		exit 1
	fi
	if ! echo "$2" | grep -qE '^[a-zA-Z0-9._\-]*$'
	then
		echo "Error: Invalid name."
		exit 1
	fi
	if ! echo "$3" | grep -qE '^[a-zA-Z0-9._\-]*$'
	then
		echo "Error: Invalid version."
		exit 1
	fi
	if [ -d $tmp ]
	then
		echo "Working project already exists."
		read -p "Proceed anyways? [y/n] " ans
		if [ "$ans" != "Y" ] && [ "$ans" != "y" ]
		then
			exit 0
		fi
		rm -rf $tmp
	fi
	mkdir -p $tmp/opt/$proj/$2/$3/run
	echo "New project created."
	exit 0
fi

if [ "$1" == "clean" ] || [ "$1" == "--clean" ]
then
	rm -rf $tmp 2>&1 1>/dev/null
	exit 0
fi

if [ ! -d $tmp ]
then
	echo "Error: Not initialized."
	exit 1
fi
ret=$(realpath .)
prefix=
pkg=
cd $tmp
prefix=$prefix/opt
cd opt
prefix=$prefix/$(ls | xargs)
cd $(ls | xargs)
prefix=$prefix/$(ls | xargs)
pkg_name=$(ls | xargs)
pkg=$pkg$(ls | xargs)-
cd $(ls | xargs)
prefix=$prefix/$(ls | xargs)
pkg_ver=$(ls | xargs)
pkg=$pkg$(ls | xargs)_
cd $(ls | xargs)
root=$(realpath .)
pkg=$pkg$(dpkg --print-architecture)
cd $ret

if [ "$1" == "tree" ]
then
	cd $root
	tree .
	cd $ret
elif [ "$1" == "add" ] || [ "$1" == "--add" ]
then
	cp $(realpath $2) $root/$3/$(basename $2)
elif [ "$1" == "global" ] || [ "$1" == "--global" ] || [ "$1" == "export" ] || [ "$1" == "--export" ]
then
	if [ "$(echo $2 | xargs)" == "" ] || [ "$2" == "help" ] || [ "$2" == "--help" ]
	then
		echo "Usage: $proj export [executable path]"
		exit 0
	fi
	file=$root/$2
	rfile=$(realpath $file)
	if [ ! -f "$root/$2" ]
	then
		echo "Error: File not found."
		exit 1
	fi
	if file $rfile | grep 'statically linked' | grep -q 'executable'
	then
		mkdir -p $tmp/usr/local/bin/
		ln -s $prefix/$2 $tmp/usr/local/bin/$(basename $file)
	else
		echo "Error: This file cannot be made global."
		exit 1
	fi
elif [ "$1" == "mkdir" ] || [ "$1" == "--mkdir" ]
then
	if [ "$2" == "run" ] || [ "$2" == "/run" ] || [ "$2" == "run/" ] || [ "$2" == "/run/" ]
	then
		echo "Error: The path \`run\` is reserved."
		exit 1
	fi
	if [ "$2" == "lib" ] || [ "$2" == "/lib" ] || [ "$2" == "lib/" ] || [ "$2" == "/lib/" ]
	then
		echo "Error: The path \`lib\` is reserved."
		exit 1
	fi
	if [ "$2" == "DEBIAN" ] || [ "$2" == "/DEBIAN" ] || [ "$2" == "DEBIAN/" ] || [ "$2" == "/DEBIAN/" ]
	then
		echo "Error: The path \`DEBIAN\` is reserved."
		exit 1
	fi
	if [ "$(echo $2 | xargs)" == "" ] || [ "$2" == "help" ] || [ "$2" == "--help" ]
	then
		echo "Usage: $proj $mkdir [directory]"
		exit 0
	fi
	if [ -d "$root/$2" ]
	then
		echo "Error: Directory already exists."
		exit 1
	fi
	mkdir $root/$2
elif [ "$1" == "import" ] || [ "$1" == "--import" ]
then
	file=$2
	if [ ! -f "$file" ]
	then
		file=$(which $file)
	fi
	if [ ! -f "$file" ]
	then
		echo "Error: Invalid file \`$2\`."
		exit 1
	fi
	if [ "$3" == "run" ] || [ "$3" == "/run" ] || [ "$3" == "run/" ] || [ "$3" == "/run/" ]
	then
		echo "Warning: The path \`run\` is reserved."
	fi
	if [ "$3" == "lib" ] || [ "$3" == "/lib" ] || [ "$3" == "lib/" ] || [ "$3" == "/lib/" ]
	then
		echo "Warning: The path \`lib\` is reserved."
	fi
	if [ "$3" == "DEBIAN" ] || [ "$3" == "/DEBIAN" ] || [ "$3" == "DEBIAN/" ] || [ "$3" == "/DEBIAN/" ]
	then
		echo "Warning: The path \`DEBIAN\` is reserved."
	fi
	if [ "$(echo $3 | xargs)" == "" ]
	then
		echo "Error: The path cannot be empty."
		exit 1
	fi
	bfile=$(basename $file)
	rfile=$(realpath $file)
	mkdir -p $root/$3
	mkdir -p $root/run/
	mkdir -p $root/lib/
	if file $rfile | grep 'dynamically linked' | grep -q 'executable'
	then
		cp $rfile $root/run/$bfile
		libs=$(lddtree $rfile | grep '=>' | sed -e 's/.*=>//' -e 's/)//' | xargs)
		count=$(echo $libs | awk '{print NF}')
		iter=1
		while [ "$iter" != "$((count+1))" ]
		do
			lib=$(echo $libs | cut -d " " -f $iter)
			cp $(realpath $lib) $root/lib/$(basename $lib)
			echo "Imported: $lib"
			iter=$((iter+1))
		done
		int=$(basename $(patchelf --print-interpreter $file))
		patchelf --set-interpreter $prefix/lib/$int $root/run/$bfile
        	echo '
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>  // for basename()

int main(int argc, char *argv[]) {
    // Determine target basename from argv[0]
    char *self_copy = strdup(argv[0]);
    if (!self_copy) return 1;
    char *base = basename(self_copy);

    // Construct target path: "'$prefix$'/run/" + basename
    char target[4096];
    if (snprintf(target, sizeof(target), "'$prefix'/run/%s", base) >= (int)sizeof(target)) {
        free(self_copy);
        return 1; // path too long
    }
    free(self_copy);

    // Build new argv: [target, argv[1], ..., NULL]
    char **new_argv = malloc((argc + 1) * sizeof(char *));
    if (!new_argv) return 1;
    new_argv[0] = target;
    for (int i = 1; i < argc; ++i) {
        new_argv[i] = argv[i];
    }
    new_argv[argc] = NULL;

    // Set LD_LIBRARY_PATH
    setenv("LD_LIBRARY_PATH", "'$prefix'/lib/", 1);

    // Execute directly
    execv(target, new_argv);

    // execv failed
    return 1;
}
'>$root/.tmp.c
		gcc $root/.tmp.c -o $root/$3/$bfile -static
		rm $root/.tmp.c
	elif file $rfile | grep 'statically linked' | grep -q 'executable'
	then
		cp $file $root/run/
		ln -s $prefix/run/$bfile $root/$3/$bfile
	else
		cp $file $root/$3/$bfile
	fi
elif [ "$1" == "build" ] || [ "$1" == "--build" ]
then
	if [ "$2" == "" ] || [ "$2" == "help" ] || [ "$2" == "--help" ]
	then
		echo "Usage: $proj build [tar|deb]"
		exit 0
	fi
	if [ "$2" == "tar" ]
	then
		cd $tmp
		touch $root/.list
		tar -cvf $ret/$pkg.tar *
		cd $ret
	elif [ "$2" == "deb" ]
	then
		mkdir -p $tmp/DEBIAN/
		echo 'Package: '$pkg_name'
Version: '$pkg_ver'
Section: other
Priority: optional
Architecture: '$(dpkg --print-architecture)'
Installed-Size: '$(du -ks $tmp | sed -e 's/\s.*//' -e 's/M//')'
Maintainer: '${proj^}' <pcalau12i@foleosoft.com>
Description: Built with '${proj^}'
'>$tmp/DEBIAN/control
		chmod 0775 $tmp/DEBIAN/control
		dpkg-deb --build $tmp $pkg.deb
		rm -rf $tmp/DEBIAN
	fi
else
	echo "Usage: $proj [init|import|export|mkdir|tree|clean|build]"
	echo "       $proj [install|uninstall|list]"
	exit 1
fi
