#!/bin/bash

set -o errexit
set -x

if ! type "git" >/dev/null 2>&1; then
	echo "The \"git\" command must be installed."
	exit 1
fi

arch="$(uname -m)"
os="$(uname -s | tr '[:upper:]' '[:lower:]')"

# init spc command, if we use spc binary, just use it instead of fetching source
if [ -z "${SPC_REL_TYPE}" ]; then
	SPC_REL_TYPE="source"
fi
# init spc libc
if [ -z "${SPC_LIBC}" ]; then
	if [ "${os}" = "linux" ]; then
		SPC_LIBC="musl"
	fi
fi
# init spc build additional args
if [ -z "${SPC_OPT_BUILD_ARGS}" ]; then
	SPC_OPT_BUILD_ARGS="--debug"
	if [ "${SPC_LIBC}" = "musl" ]; then
		SPC_OPT_BUILD_ARGS="${SPC_OPT_BUILD_ARGS} --disable-opcache-jit"
	fi
fi
# init spc download additional args
if [ -z "${SPC_OPT_DOWNLOAD_ARGS}" ]; then
	if [ "${SPC_LIBC}" = "musl" ]; then
		SPC_OPT_DOWNLOAD_ARGS="--prefer-pre-built --ignore-cache-sources=php-src"
	else
		SPC_OPT_DOWNLOAD_ARGS="--ignore-cache-sources=php-src"
	fi
fi
# if we need debug symbols, disable strip
if [ -n "${DEBUG_SYMBOLS}" ]; then
	SPC_OPT_BUILD_ARGS="${SPC_OPT_BUILD_ARGS} --no-strip"
fi
# php version to build
if [ -z "${PHP_VERSION}" ]; then
	get_latest_php_version() {
		input="$1"
		json=$(curl -s "https://www.php.net/releases/index.php?json&version=$input")
		latest=$(echo "$json" | jq -r '.version')

		if [[ "$latest" == "$input"* ]]; then
			echo "$latest"
		else
			echo "$input"
		fi
	}

	PHP_VERSION="$(get_latest_php_version "8.3")"
	export PHP_VERSION
fi
# default extension set
# gmp causes crashes on older CPU archs, so we cannot include it
defaultExtensions="apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gettext,iconv,igbinary,imagick,intl,ldap,libxml,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,parallel,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,ssh2,sysvmsg,sysvsem,sysvshm,tidy,tokenizer,xlswriter,xml,xmlreader,xmlwriter,xsl,zip,zlib,yaml,zstd"
# if [ "${os}" != "linux" ] || [ "${SPC_LIBC}" = "glibc" ]; then
# 	defaultExtensions="${defaultExtensions},ffi"
# fi
defaultExtensionLibs="bzip2,freetype,libavif,libjpeg,liblz4,libwebp,libzip,nghttp2"

md5binary="md5sum"
if [ "${os}" = "darwin" ]; then
	os="mac"
	md5binary="md5 -q"
fi

if [ "${os}" = "linux" ] && ! type "cmake" >/dev/null 2>&1; then
	echo "The \"cmake\" command must be installed."
	exit 1
fi

if [ "${os}" = "linux" ] && { [[ "${arch}" =~ "aarch" ]] || [[ "${arch}" =~ "arm" ]]; }; then
	fpic="-fPIC"
	fpie="-fPIE"

	if [ -z "${DEBUG_SYMBOLS}" ]; then
		export SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS="-g -fstack-protector-strong -fPIC -fPIE -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
	fi
else
	fpic="-fpic"
	fpie="-fpie"
fi

if [ -z "${SOLIDINVOICE_VERSION}" ]; then
	SOLIDINVOICE_VERSION="$(git rev-parse --verify HEAD)"
	export SOLIDINVOICE_VERSION
elif [ -d ".git/" ]; then
	CURRENT_REF="$(git rev-parse --abbrev-ref HEAD)"
	export CURRENT_REF

	if echo "${SOLIDINVOICE_VERSION}" | grep -F -q "."; then
		# Tag

		# Trim "v" prefix if any
		SOLIDINVOICE_VERSION=${SOLIDINVOICE_VERSION#v}
		export SOLIDINVOICE_VERSION

		git checkout "v${SOLIDINVOICE_VERSION}"
	else
		git checkout "${SOLIDINVOICE_VERSION}"
	fi
fi

bin="solidinvoice-${os}-${arch}"

if [ -n "${CLEAN}" ]; then
	rm -Rf dist/
	go clean -cache
fi


mkdir -p dist/
cd dist/

if type "brew" >/dev/null 2>&1; then
	if ! type "composer" >/dev/null; then
		packages="composer"
	fi
	if ! type "go" >/dev/null 2>&1; then
		packages="${packages} go"
	fi
	if [ -n "${RELEASE}" ] && ! type "gh" >/dev/null 2>&1; then
		packages="${packages} gh"
	fi

	if [ -n "${packages}" ]; then
		# shellcheck disable=SC2086
		brew install --formula --quiet ${packages}
	fi
fi

if [ "${SPC_REL_TYPE}" = "binary" ]; then
	mkdir -p static-php-cli/
	cd static-php-cli/
	if [[ "${arch}" =~ "arm" ]]; then
		dl_arch="aarch64"
	else
		dl_arch="${arch}"
	fi
	curl -o spc -fsSL "https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-${dl_arch}"
	chmod +x spc
	spcCommand="./spc"
elif [ -d "static-php-cli/src" ]; then
	cd static-php-cli/
	git pull
	composer install --no-dev -a --no-interaction
	spcCommand="./bin/spc"
else
	git clone --depth 1 https://github.com/crazywhalecc/static-php-cli --branch main
	cd static-php-cli/
	composer install --no-dev -a --no-interaction
	spcCommand="./bin/spc"
fi

#PHP_EXTENSIONS=$(${spcCommand} dump-extensions "../../../" --format=text --no-dev --no-ext-output="${defaultExtensions}")
PHP_EXTENSIONS="${defaultExtensions}"
# additional libs to build
if [ -z "${PHP_EXTENSION_LIBS}" ]; then
	PHP_EXTENSION_LIBS="${defaultExtensionLibs}"
fi

# The Brotli library must always be built as it is required by http://github.com/dunglas/caddy-cbrotli
if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bbrotli\b"; then
	PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},brotli"
fi

# The mimalloc library must be built if MIMALLOC is true
if [ -n "${MIMALLOC}" ]; then
	if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bmimalloc\b"; then
		PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},mimalloc"
	fi
fi

# Build libphp if necessary
cache_key="${PHP_VERSION}-${PHP_EXTENSIONS}-${PHP_EXTENSION_LIBS}"
if [ -f ./cache_key ] && [ "$(cat ./cache_key)" = "${cache_key}" ] && [ -f "buildroot/lib/libphp.a" ]; then
	echo "Hit cache, skipping libphp build."
else
	${spcCommand} doctor --auto-fix
	# shellcheck disable=SC2086
	${spcCommand} download --with-php="${PHP_VERSION}" --for-extensions="${PHP_EXTENSIONS}" --for-libs="${PHP_EXTENSION_LIBS}" ${SPC_OPT_DOWNLOAD_ARGS}
	# shellcheck disable=SC2086
	${spcCommand} build --enable-zts --build-embed ${SPC_OPT_BUILD_ARGS} "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}"

	echo -n "${cache_key}" >./cache_key
fi

if ! type "go" >/dev/null 2>&1; then
	echo "The \"go\" command must be installed."
	exit 1
fi


# See https://github.com/docker-library/php/blob/master/8.3/alpine3.20/zts/Dockerfile#L53-L55
CGO_CFLAGS="-DSOLIDINVOICE_VERSION=${SOLIDINVOICE_VERSION} -I${PWD}/buildroot/include/ $(${spcCommand} spc-config "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}" --includes)"
if [ -n "${DEBUG_SYMBOLS}" ]; then
	CGO_CFLAGS="-g ${CGO_CFLAGS}"
else
	CGO_CFLAGS="-fstack-protector-strong ${fpic} ${fpie} -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 ${CGO_CFLAGS}"
fi
export CGO_CFLAGS
export CGO_CPPFLAGS="${CGO_CFLAGS}"

if [ "${os}" = "mac" ]; then
	export CGO_LDFLAGS="-framework CoreFoundation -framework SystemConfiguration"
elif [ "${os}" = "linux" ] && [ -z "${DEBUG_SYMBOLS}" ]; then
	CGO_LDFLAGS="-Wl,-O1 -pie"
fi
if [ "${os}" = "linux" ] && [ "${SPC_LIBC}" = "glibc" ]; then
	CGO_LDFLAGS="${CGO_LDFLAGS} -Wl,--allow-multiple-definition -Wl,--export-dynamic"
fi

CGO_LDFLAGS="${CGO_LDFLAGS} ${PWD}/buildroot/lib/libbrotlicommon.a ${PWD}/buildroot/lib/libbrotlienc.a ${PWD}/buildroot/lib/libbrotlidec.a $(${spcCommand} spc-config "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}" --libs)"
if [[ "$CGO_LDFLAGS" == *"${PWD}/buildroot/lib/mimalloc.o"* ]]; then
	CGO_LDFLAGS=${CGO_LDFLAGS//${PWD}\/buildroot\/lib\/mimalloc.o/}
	CGO_LDFLAGS="${PWD}/buildroot/lib/libmimalloc.a $CGO_LDFLAGS"
fi
if [ "${os}" = "linux" ] && [ "${SPC_LIBC}" = "glibc" ]; then
	CGO_LDFLAGS="${CGO_LDFLAGS//-lphp/-Wl,--whole-archive -lphp -Wl,--no-whole-archive}"
	# shellcheck disable=SC2046
	ar d "${PWD}/buildroot/lib/libphp.a" $(ar t "${PWD}/buildroot/lib/libphp.a" | grep '\.a$')
fi

export CGO_LDFLAGS

LIBPHP_VERSION="$(./buildroot/bin/php-config --version)"

cd ../

if [ -z "${DEBUG_SYMBOLS}" ]; then
	extraLdflags="-w -s"
fi

cd ../

${md5binary} app.tar.gz | awk '{printf $1}' >app_checksum.txt

if [ "${SPC_LIBC}" = "musl" ]; then
	muslStackSizeFix="-Wl,-z,stack-size=0x80000"
fi

go env

if [ -z "${SPC_LIBC}" ] || [ "${SPC_LIBC}" = "musl" ]; then
	# shellcheck disable=SC2054
	goBuildFlags=(
		-buildmode=pie
		-tags cgo,netgo,osusergo,static_build,nobadger,nowatcher,nomysql,nopgx
		-ldflags
		"-linkmode=external -extldflags '-static-pie ${muslStackSizeFix}' ${extraLdflags} -X 'github.com/caddyserver/caddy/v2.CustomVersion=SolidInvoice ${SOLIDINVOICE_VERSION} PHP ${LIBPHP_VERSION} Caddy'"
	)
elif [ "${SPC_LIBC}" = "glibc" ]; then
	# shellcheck disable=SC2054
	goBuildFlags=(
		-buildmode=pie
		-tags cgo,netgo,osusergo,nobadger,nowatcher,nomysql,nopgx
		-ldflags
		"-linkmode=external -extldflags '-pie' ${extraLdflags} -X 'github.com/caddyserver/caddy/v2.CustomVersion=SolidInvoice ${SOLIDINVOICE_VERSION} PHP ${LIBPHP_VERSION} Caddy'"
	)
fi

# shellcheck disable=SC2086
CGO_ENABLED=1 \
	go build "${goBuildFlags[@]}" \
	-o "./dist/${bin}" \


if type "upx" >/dev/null 2>&1 && [ -z "${DEBUG_SYMBOLS}" ] && [ -z "${NO_COMPRESS}" ]; then
	upx --best "dist/${bin}"
fi

"dist/${bin}" version
#"dist/${bin}" build-info

if [ "${RELEASE:-}" = "1" ]; then
	gh release upload "${SOLIDINVOICE_VERSION}" "dist/${bin}" --repo solidinvoice/solidinvoice --clobber
fi

if [ -n "${CURRENT_REF}" ]; then
	git checkout "${CURRENT_REF}"
fi

if [ -n "${TARGETARCH}" ]; then
	mv "dist/${bin}" "dist/solidinvoice-${TARGETOS}-${TARGETARCH}"
fi
