set shell := ["sh", "-cuo", "pipefail"]

oat_version := "0.6.2"
alicia_rev := "6c2ccc47f1f2ae46777db6181481e17bb63ee4c4"

[private]
default:
	@just --list
[doc("Fetches vendored dependencies from the internet into the 
./vendor/ directory, refetching when their set revision
(set atop the justfile) changes.")]
vendor:
	# Fetch vendored pkgs as tarballs, & re-fetch when there are changes!
	[ "$(cat ./vendor/alicia/.rev 2>/dev/null)" = "{{ alicia_rev }}" ] || { \
		rm -rf ./vendor/alicia && mkdir -p ./vendor/alicia && \
		curl -fsSL --retry 3 --retry-delay 2 https://tangled.org/sheetr.app/alicia/archive/{{ alicia_rev }}.tar.gz | tar -xz -C ./vendor/alicia --strip-components=1 && \
		echo "{{ alicia_rev }}" > ./vendor/alicia/.rev; \
	}
	
	
	[ "$(cat ./vendor/oat/.rev 2>/dev/null)" = "{{ oat_version }}" ] || { \
		rm -rf ./vendor/oat && mkdir -p ./vendor/oat && \
		curl https://unpkg.com/@knadh/oat@{{ oat_version }}/oat.min.js -o ./vendor/oat/oat.min.js && \
		curl https://unpkg.com/@knadh/oat@{{ oat_version }}/oat.min.css -o ./vendor/oat/oat.min.css && \
		echo "{{ oat_version }}" > ./vendor/oat/.rev; \
	}

[doc("Prepares for building the application, this consists
out of a multitude of steps, including the building and
bundling of the client's javascript and style bundles.")]
prepare-build: vendor
	# Write prelude to SPA src directory
	[ ! -f ./frontend/client/prelude.mts ] && gleam export typescript-prelude > ./frontend/client/prelude.mts || echo ""

	# Build SPA
	cd ./frontend/client/ && { gleam build --target javascript || { echo "stale gleam cache, cleaning and retrying" ; gleam clean && gleam build --target javascript ; } ; }

	# Create bundleable export from Oat's JS.
	echo 'export function oat () {' > ./frontend/client/build/dev/javascript/bowtie_client/oat.mjs
	cat ./vendor/oat/oat.min.js >> ./frontend/client/build/dev/javascript/bowtie_client/oat.mjs
	echo '}' >> ./frontend/client/build/dev/javascript/bowtie_client/oat.mjs

	# Patch SPA, Oat and Lustre Server Component runtime into a single web js bundle.
	echo 'import { main } from "./bowtie_client.mjs"; import { ServerComponent } from "../lustre/priv/static/lustre-server-component.mjs"; import { oat } from "./oat.mjs"; document.addEventListener("DOMContentLoaded", () => main()); oat()' > "./frontend/client/build/dev/javascript/bowtie_client/client.mjs"
	deno bundle -o ./backend/priv/client.js --platform=browser ./frontend/client/build/dev/javascript/bowtie_client/client.mjs
	deno bundle -o ./backend/priv/client.min.js --platform=browser --minify ./frontend/client/build/dev/javascript/bowtie_client/client.mjs

	# Bundle Oat into web css bundle.
	printf "/*\n* Bowtie\n* Copyright (C) 2018-2026 MLC 'Strawmelonjuice' Bloeiman and contributors.\n*\n* This software is licensed under the European Union Public Licence (EUPL) v1.2.\n* You may not use this work except in compliance with the Licence.\n* You may obtain a copy of the Licence at: https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n*\n* or see the LICENCE file in the repository root for full details.\n*\n*\n* This software is provided \"AS IS\", WITHOUT WARRANTY OF ANY KIND.\n* See the Licence for the specific language governing permissions and limitations.\n*\n* This bundled file also contains CSS contents for Oat CSS, which is licenced under MIT <https://github.com/knadh/oat/blob/master/LICENSE>. Big thank you to Kailash Nadh for this library.\n*/" > "./backend/priv/bowtie.css"
	printf "\n\n/* Oat.css {{ oat_version }} */\n" >> "./backend/priv/bowtie.css"
	cat ./vendor/oat/oat.min.css >> "./backend/priv/bowtie.css"
	# And Bowtie's own.
	printf "\n\n/* Bowtie's own styles */\n" >> "./backend/priv/bowtie.css"
	cat ./backend/priv/static/bowtie-base.css >> "./backend/priv/bowtie.css"

	# Minify the css bundle
	deno x minifier backend/priv/bowtie.css --output backend/priv/bowtie.min.css

	# Also copy over other files, such as licence file.
	cp ./LICENCE ./backend/priv/licence


[doc("Build and runs the full application.
For development use.")]
run: prepare-build
	# Build and run backend.
	cd ./backend && { gleam build || { echo "stale gleam cache, cleaning and retrying" ; gleam clean && gleam build ; } ; } && gleam run
 
[doc("Build client as preparation, then build and run
backend.")]
build: prepare-build
	# Build and run backend.
	cd ./backend && { gleam export erlang-shipment || { echo "stale gleam cache, cleaning and retrying" ; gleam clean && gleam export erlang-shipment ; } ; }
	echo "With this erlang shipment we now either build a Podman image or I'll have to put something in the Flake, whatever"

[doc("Build and runs the full application, with a 
file watcher to immediately rebuild on change.
For development use.")]
dev $START_OBSERVER='1':
	watchexec --restart --verbose --wrap-process=session --stop-signal SIGTERM --exts gleam,mjs,mts,djot,css,erl --debounce 500ms -- just run

[doc("Runs both tests for client and backend.")]
[parallel]
test: test-backend test-client

[doc("Runs tests for backend.")]
test-backend: prepare-build
	# Build and test backend.
	cd ./backend && { gleam build || { echo "stale gleam cache, cleaning and retrying" ; gleam clean && gleam build ; } ; } && gleam test

[doc("Runs tests for client, both running on the Erlang target and on Deno, to ensure consistency.")]
test-client: prepare-build
	# Build and test client.
	cd ./frontend/client/ && { gleam build --target javascript || { echo "stale gleam cache, cleaning and retrying" ; gleam clean && gleam build --target javascript ; } ; }
	cd ./frontend/client/ && gleam test --target erlang # For when ran from the backend.
	cd ./frontend/client/ && gleam test --target javascript --runtime deno

