#!/bin/bash

## shfmt -w -s -bn -ci -sr -fn scripts/packaging/build/dependencies/build-dependencies.sh

set -e          # Exit immediately if a command exits with a non-zero status
set -u          # Treat unset variables as an error
set -o pipefail # Return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status
set -x          # Print commands and their arguments as they are executed

# Default values
BUILD_NUMBER=${BUILD_NUMBER:-42}
LIBRARIES=()
BUILD_ALL=false
SETUP_ENV=false
OUTPUT_DIR="/var/local/deb"
SOURCE_PREFIX="/usr/src"
SETUP_LOCAL_REPO=false
CLONE_REPOS=false
GIT_PROTOCOL="ssh"

###################
# Helper Functions
###################

# Display script usage information and available options
function show_usage()
{
	echo "Usage: $0 [options] [library_names...]"
	echo "Options:"
	echo "  -h, --help            Show this help message"
	echo "  -b, --build-number N  Set build number (default: 42 or env value)"
	echo "  -a, --all             Build all libraries"
	echo "  -s, --setup           Set up build environment before building"
	echo "  -o, --output DIR      Set output directory (default: /var/local/deb)"
	echo "  -p, --prefix DIR      Set source path prefix (default: /usr/src)"
	echo "  -r, --repo            Set up local repository after building"
	echo "  -c, --clone           Clone required repositories before building"
	echo "  -g, --git-https       Use HTTPS instead of SSH for git cloning"
	echo ""
	echo "Available libraries:"
	echo "  libbroadvoice"
	echo "  libilbc"
	echo "  libsilk"
	echo "  spandsp"
	echo "  sofia-sip"
	echo "  libks"
	echo "  signalwire-c"
	echo "  libv8-packaging (or libv8)"
	echo ""
}

# Normalize library names, replacing aliases with their canonical names
function normalize_library_name()
{
	local lib_name=$1

	case $lib_name in
		libv8)
			echo "libv8-packaging"
			;;
		*)
			echo "$lib_name"
			;;
	esac
}

# Parse command line arguments and set corresponding variables
function parse_arguments()
{
	while [[ $# -gt 0 ]]; do
		case $1 in
			-h | --help)
				show_usage
				exit 0
				;;
			-b | --build-number)
				BUILD_NUMBER="$2"
				shift 2
				;;
			-a | --all)
				BUILD_ALL=true
				shift
				;;
			-s | --setup)
				SETUP_ENV=true
				shift
				;;
			-o | --output)
				OUTPUT_DIR="$2"
				shift 2
				;;
			-p | --prefix)
				SOURCE_PREFIX="$2"
				shift 2
				;;
			-r | --repo)
				SETUP_LOCAL_REPO=true
				shift
				;;
			-c | --clone)
				CLONE_REPOS=true
				shift
				;;
			-g | --git-https)
				GIT_PROTOCOL="https"
				shift
				;;
			*)
				local normalized_name=$(normalize_library_name "$1")
				LIBRARIES+=("$normalized_name")
				shift
				;;
		esac
	done

	if [ "$(id -u)" != "0" ]; then
		echo "Non-root user detected. Execution may fail."
	fi
}

# Validate the provided arguments and set defaults if needed
function validate_arguments()
{
	if [ ${#LIBRARIES[@]} -eq 0 ] && [ "$BUILD_ALL" == "false" ]; then
		echo "Error: No libraries specified"
		show_usage
		exit 1
	fi

	if [ "$BUILD_ALL" == "true" ]; then
		LIBRARIES=("libbroadvoice" "libilbc" "libsilk" "spandsp" "sofia-sip" "libks" "signalwire-c" "libv8-packaging")
	fi
}

# Set up the build environment variables and create output directory
function setup_environment()
{
	export DEBIAN_FRONTEND=noninteractive
	export BUILD_NUMBER=$BUILD_NUMBER
	export CODENAME=$(lsb_release -sc)

	mkdir -p "$OUTPUT_DIR"
}

# Install required build tools and dependencies
function setup_build_environment()
{
	export DEBIAN_FRONTEND=noninteractive

	local tmp_dir="${TMPDIR:-/tmp}"

	echo "Setting up build environment..."
	apt-get update \
		&& apt-get -y upgrade \
		&& apt-get -y install \
			build-essential \
			cmake \
			devscripts \
			lsb-release \
			docbook-xsl \
			pkg-config \
			git

	if ! git config --global --get-all safe.directory | grep -q '\*'; then
		echo "Setting git safe.directory configuration..."
		git config --global --add safe.directory '*'
	fi

	if [[ " ${LIBRARIES[@]} " =~ " libv8-packaging " ]] || [ "$BUILD_ALL" == "true" ]; then
		echo "libv8 is in the build list, checking for dependencies..."

		if [ ! -d "$SOURCE_PREFIX/libv8-packaging" ] && [ "$CLONE_REPOS" == "true" ]; then
			echo "Cloning libv8-packaging repository..."
			clone_repositories "libv8-packaging"
		fi

		if [ -d "$SOURCE_PREFIX/libv8-packaging" ] && [ -f "$SOURCE_PREFIX/libv8-packaging/build.sh" ]; then
			echo "Installing dependencies for libv8..."
			(cd "$SOURCE_PREFIX/libv8-packaging" && ./build.sh --install-deps)

			echo "Setting up Python environment for libv8..."
			(cd "$SOURCE_PREFIX/libv8-packaging" && ./build.sh --setup-pyenv)
			touch "${tmp_dir}/libv8_pyenv_setup_complete"
		else
			echo "Warning: libv8-packaging directory not found. Clone the repository first to install its dependencies."
			echo "You can use the --clone flag or run the script with -c libv8-packaging first."
		fi
	fi
}

# Clone a specific library repository using the configured protocol
clone_repositories()
{
	local lib_name=$1
	local original_dir=$(pwd)
	local repo_dir="$SOURCE_PREFIX/$lib_name"

	echo "=== Cloning $lib_name ==="

	if [ -d "$repo_dir" ]; then
		echo "Directory $repo_dir already exists, skipping clone..."
		return 0
	fi

	mkdir -p "$SOURCE_PREFIX"
	cd "$SOURCE_PREFIX"

	if [ "$GIT_PROTOCOL" == "ssh" ]; then
		FREESWITCH_BASE="git@github.com:freeswitch"
		SIGNALWIRE_BASE="git@github.com:signalwire"
	else
		FREESWITCH_BASE="https://github.com/freeswitch"
		SIGNALWIRE_BASE="https://github.com/signalwire"
	fi

	case $lib_name in
		libbroadvoice)
			git clone $FREESWITCH_BASE/libbroadvoice.git
			;;
		libilbc)
			git clone $FREESWITCH_BASE/libilbc.git
			;;
		libsilk)
			git clone $FREESWITCH_BASE/libsilk.git
			;;
		spandsp)
			git clone --branch packages $FREESWITCH_BASE/spandsp.git
			;;
		sofia-sip)
			git clone $FREESWITCH_BASE/sofia-sip.git
			;;
		libks)
			git clone $SIGNALWIRE_BASE/libks.git
			;;
		signalwire-c)
			git clone $SIGNALWIRE_BASE/signalwire-c.git
			;;
		libv8-packaging)
			git clone $FREESWITCH_BASE/libv8-packaging.git
			;;
		*)
			echo "Error: Unknown library for cloning '$lib_name'"
			return 1
			;;
	esac

	cd "$original_dir"

	echo "=== Completed cloning $lib_name ==="
}

# Set up a local Debian repository for built packages
setup_local_repository()
{
	local original_dir=$(pwd)
	local abs_output_dir=$(readlink -f "$OUTPUT_DIR")

	echo "Setting up local Debian repository in $abs_output_dir..."
	cd "$abs_output_dir"

	dpkg-scanpackages -m . | tee Packages \
		&& gzip -f -k Packages \
		&& printf "deb [trusted=yes] file:$abs_output_dir /\n" | tee /etc/apt/sources.list.d/local.list \
		&& apt-get update

	cd "$original_dir"

	echo "Local repository setup complete."
}

# Build a library using the Debian package build system
build_deb_library()
{
	local lib_name=$1
	local original_dir=$(pwd)

	echo "=== Building $lib_name ==="

	cd "$SOURCE_PREFIX/$lib_name/"

	export VERSION=$(dpkg-parsechangelog --show-field Version | cut -f1 -d'-')
	export GIT_SHA=$(git rev-parse --short HEAD)

	echo "Version: $VERSION"
	echo "Git SHA: $GIT_SHA"
	echo "Build Number: $BUILD_NUMBER"

	apt-get update \
		&& mk-build-deps \
			--install \
			--remove debian/control \
			--tool "apt-get -y --no-install-recommends" \
		&& apt-get -y -f install

	dch \
		--controlmaint \
		--distribution "${CODENAME}" \
		--force-bad-version \
		--force-distribution \
		--newversion "${VERSION}-${BUILD_NUMBER}-${GIT_SHA}~${CODENAME}" \
		"Nightly build, ${GIT_SHA}" \
		&& debuild \
			--no-tgz-check \
			--build=binary \
			--unsigned-source \
			--unsigned-changes \
		&& mv -v ../*.{deb,changes} "$OUTPUT_DIR"/.

	cd "$original_dir"

	echo "=== Completed building $lib_name ==="
}

# Build a library using the CMake build system
build_cmake_library()
{
	local lib_name=$1
	local deps=$2
	local original_dir=$(pwd)

	echo "=== Building $lib_name ==="

	cd "$SOURCE_PREFIX/$lib_name/"

	if [ -n "$deps" ]; then
		echo "Installing dependencies for $lib_name..."
		apt-get update && apt-get -y install $deps
	fi

	export GIT_SHA=$(git rev-parse --short HEAD)

	echo "Git SHA: $GIT_SHA"
	echo "Build Number: $BUILD_NUMBER"

	PACKAGE_RELEASE="${BUILD_NUMBER}.${GIT_SHA}" cmake . \
		-DCMAKE_BUILD_TYPE=Debug \
		-DCMAKE_INSTALL_PREFIX="/usr" \
		&& make package \
		&& mv -v *.deb "$OUTPUT_DIR"/.

	cd "$original_dir"

	echo "=== Completed building $lib_name ==="
}

# Build libv8 using its own build script
build_libv8()
{
	local original_dir=$(pwd)
	local tmp_dir="${TMPDIR:-/tmp}"
	local pyenv_marker_file="${tmp_dir}/libv8_pyenv_setup_complete"

	echo "=== Building libv8 ==="

	cd "$SOURCE_PREFIX/libv8-packaging/"

	echo "Building libv8 with build number $BUILD_NUMBER, output to $OUTPUT_DIR..."
	./build.sh --build-number "$BUILD_NUMBER" --output-dir "$OUTPUT_DIR"

	cd "$original_dir"

	echo "=== Completed building libv8-packaging ==="
}

# Process dependencies and ensure they're built in the correct order
function process_dependencies()
{
	local NEEDS_LOCAL_REPO=false

	if [[ " ${LIBRARIES[@]} " =~ " signalwire-c " ]]; then
		NEEDS_LOCAL_REPO=true

		if ! [[ " ${LIBRARIES[@]} " =~ " libks " ]]; then
			echo "Adding libks as a dependency for signalwire-c"
			LIBRARIES=("libks" "${LIBRARIES[@]}")
		fi
	fi

	echo $NEEDS_LOCAL_REPO
}

# Clone all the repositories for the specified libraries
function clone_all_repos()
{
	echo "Cloning repositories using ${GIT_PROTOCOL} protocol..."
	for lib in "${LIBRARIES[@]}"; do
		clone_repositories "$lib"
	done
}

# Build all the specified libraries in the correct order
function build_all_libraries()
{
	local NEEDS_LOCAL_REPO=$(process_dependencies)

	for lib in "${LIBRARIES[@]}"; do
		case $lib in
			libbroadvoice | libilbc | libsilk | spandsp | sofia-sip)
				build_deb_library "$lib"
				;;
			libks)
				build_cmake_library "$lib" "libssl-dev uuid-dev"
				;;
			signalwire-c)
				setup_local_repository
				build_cmake_library "$lib" "libks2"
				;;
			libv8-packaging)
				build_libv8
				;;
			*)
				echo "Error: Unknown library '$lib'"
				show_usage
				exit 1
				;;
		esac
	done

	if [ "$SETUP_LOCAL_REPO" == "true" ] || [ "$NEEDS_LOCAL_REPO" == "false" ]; then
		setup_local_repository
		echo "Local Debian repository has been set up at $OUTPUT_DIR."
	fi
}

# Print a summary of the build process
function print_summary()
{
	echo "All selected libraries have been built successfully."
	echo "Output packages are in $OUTPUT_DIR/"
}

#####################
# Main Script Logic
#####################

# Parse command line arguments
parse_arguments "$@"

# Validate input arguments
validate_arguments

# Setup the build environment if flag is set
if [ "$SETUP_ENV" == "true" ]; then
	setup_build_environment
else
	echo "Skipping build environment setup (use -s or --setup to enable)"
fi

# Set up environment variables
setup_environment

echo "Using source path prefix: $SOURCE_PREFIX"

# Clone repositories if flag is set
if [ "$CLONE_REPOS" == "true" ]; then
	clone_all_repos
else
	echo "Skipping repository cloning (use -c or --clone to enable)"
fi

# Build all libraries
build_all_libraries

# Print summary
print_summary
