#!/usr/bin/env bash

gemtext2gophermap() {
	MAP_FILE="gopher/specific/$(basename "$1").map"
	if [[ -f "$MAP_FILE" ]]; then
		gemtext2gophermap/gemtext2gophermap - - 69 "$MAP_FILE" >> "$1/gophermap"
	else
		gemtext2gophermap/gemtext2gophermap - - 69 >> "$1/gophermap"
	fi
}

getMarkdownPath() {
	echo "src/content/posts/$(basename "$1").md"
}
getPostProperties() {
	grep -zoP "(?s)(---.*?---)" "$1" | head -zn 1 | tr -d '\0'
}

getTranslations() {
	grep -zoP "(?s)id[ ']*:[ ']*$1.*?(?=\n-[ ']*id|$)" src/content/languages.yaml | tr -d '\0'
}
getAuthor() {
	grep -zoP "(?s)id[ ']*:[ ']*$1.*?(?=\n-[ ']*id|$)" src/content/authors.yaml | tr -d '\0'
}

getTextProperty() {
	echo "$1" | grep -oPm 1 "$2:\K.+" | xargs
}
getArrayProperty() {
	echo "$1" | grep -oPm 1 "$2: *\[\K(.*?)(?=\])"
}

MARKDOWN_POST="$(getMarkdownPath "$1")"
POST_PROPERTIES="$(getPostProperties "$MARKDOWN_POST")"

GOPHER_POST_DIR="$1"
POST_ID="$(basename "$1")"
LANGUAGE="$(getTextProperty "$POST_PROPERTIES" language)"
TITLE="$(getTextProperty "$POST_PROPERTIES" title)"
AUTHORS="$(getArrayProperty "$POST_PROPERTIES" authors)"
RELATED_POSTS="$(getArrayProperty "$POST_PROPERTIES" relatedPosts)"
IS_FEATURED_INSTEAD_OF_RELATED="$(getTextProperty "$POST_PROPERTIES" featuredInsteadOfRelated)"
ALTERNATIVE_LANGUAGE_POSTS="$(getArrayProperty "$POST_PROPERTIES" alternativeLanguagesPosts)"
PUBLISHED_DATE="$(getTextProperty "$POST_PROPERTIES" publishedDate)"
UPDATED_DATE="$(getTextProperty "$POST_PROPERTIES" updatedDate)"
SHOULD_HIDE_TITLE="$(getTextProperty "$POST_PROPERTIES" hideTitle)"
SHOULD_PREPEND_LOGO="$(getTextProperty "$POST_PROPERTIES" gopherPrependLogo)"

TRANSLATIONS="$(getTranslations "$LANGUAGE")"
LANGUAGE_NAME="$(getTextProperty "$TRANSLATIONS" name)"
TRANSLATION_LATEST="$(getTextProperty "$TRANSLATIONS" latest)"
TRANSLATION_RELATED="$(getTextProperty "$TRANSLATIONS" related)"
TRANSLATION_FEATURED="$(getTextProperty "$TRANSLATIONS" featured)"
TRANSLATION_PUBLISHED_ON="$(getTextProperty "$TRANSLATIONS" publishedOn)"
TRANSLATION_LAST_UPDATED_ON="$(getTextProperty "$TRANSLATIONS" lastUpdatedOn)"
TRANSLATION_AVAILABLE_IN_OTHER_LANGUAGES="$(getTextProperty "$TRANSLATIONS" availableInOtherLanguages)"

mkdir -p "$1"

if [[ "$SHOULD_HIDE_TITLE" != 'true' ]]; then
	printf '# %s\n\n' "$TITLE" > $1/index.gmi
	printf '!%s\n' "$TITLE" > $1/gophermap
fi

DEFAULT_IFS="$IFS"
SCRIPT_DIRECTORY="$(dirname $0)"

printLogo() {
	echo '```'
	cat "$SCRIPT_DIRECTORY/logo.txt"
	echo '```'
}

generateHeader() {
	IFS=','

	if [[ "$SHOULD_PREPEND_LOGO" == 'true' ]]; then
		printf '\n' >> "$GOPHER_POST_DIR/gophermap"
		printLogo
	fi

	if [[ -n "$AUTHORS" ]]; then
		for author_id in $AUTHORS; do
			author_id="$(echo "$author_id" | xargs)"
			author_properties="$(getAuthor "$author_id")"
			author_name="$(getTextProperty "$author_properties" name)"
			author_callsign="$(getTextProperty "$author_properties" callsign)"
			author_bioPostId="$(getTextProperty "$author_properties" bioPostId)"

			if [[ -n "$author_bioPostId" ]]; then
				printf '=> /%s/ ' "$author_bioPostId"
			fi
			printf "$author_name"
			if [[ -n "$author_callsign" ]]; then
				printf ' (%s)' "$author_callsign"
			fi
			printf '\n'
		done
	fi

	if [[ -n "$ALTERNATIVE_LANGUAGE_POSTS" ]]; then
		if [[ -n "$AUTHORS" ]]; then
			printf '\n'
		fi
		for post_id in $ALTERNATIVE_LANGUAGE_POSTS; do
			post_id="$(echo "$post_id" | xargs)"
			post_path="$(getMarkdownPath "$post_id")"
			post_properties="$(getPostProperties "$post_path")"
			post_language_id="$(getTextProperty "$post_properties" language)"
			translations="$(getTranslations "$post_language_id")"
			language_name="$(getTextProperty "$translations" name)"
			printf '=> %s %s: %s\n' "/$post_id/" "$TRANSLATION_AVAILABLE_IN_OTHER_LANGUAGES" "$language_name"
		done
	fi

	if [[ -n "$PUBLISHED_DATE" || -n "$UPDATED_DATE" ]]; then
		printf '```\n'
		if [[ -n "$PUBLISHED_DATE" ]]; then
			printf '%s: %s\n' "$TRANSLATION_PUBLISHED_ON" "$PUBLISHED_DATE"
		fi
		if [[ -n "$UPDATED_DATE" ]]; then
			printf '%s: %s\n' "$TRANSLATION_LAST_UPDATED_ON" "$UPDATED_DATE"
		fi
		printf '```\n'
	else
		printf '\n'
	fi

	cat
}

generateFooter() {
	IFS=','
	if [[ -n "$RELATED_POSTS" ]]; then
		if [[ "$IS_FEATURED_INSTEAD_OF_RELATED" == 'true' ]]; then
			printf '## %s\n' "$TRANSLATION_FEATURED"
		else
			printf '## %s\n' "$TRANSLATION_RELATED"
		fi
		for post_id in $RELATED_POSTS; do
			post_id="$(echo "$post_id" | xargs)"
			post_path="$(getMarkdownPath "$post_id")"
			post_properties="$(getPostProperties "$post_path")"
			post_title="$(getTextProperty "$post_properties" title)"
			post_published_date="$(getTextProperty "$post_properties" publishedDate)"
			printf '=> %s %s %s\n' "/$post_id/" "$post_published_date" "$post_title"
		done
	fi
}

generateMainMenu() {
	declare -A menu_items
	IFS="$DEFAULT_IFS"

	for post_path in src/content/posts/*.md; do
		post_properties="$(getPostProperties "$post_path")"
		post_id="$(basename "$post_path" | sed 's/.md//')"
		if [[ "$(getTextProperty "$post_properties" putInMainMenu)" == 'true' && "$(getTextProperty "$post_properties" language)" == "$LANGUAGE" && "$post_id" != "$POST_ID" ]]; then
			main_menu_title="$(getTextProperty "$post_properties" mainMenuTitle)"
			main_menu_priority="$(getTextProperty "$post_properties" mainMenuPriority)"
			data=("$post_id" "$main_menu_title")
			printf -v data_str '%q ' "${data[@]}"
			menu_items["$main_menu_priority"]="$data_str"
		fi
	done

	mapfile -d '' sorted_menu_indexes < <(printf '%s\0' "${!menu_items[@]}" | sort -z)

	for index in "${sorted_menu_indexes[@]}"; do
		printf -v array_cmd "%q=( %s )" "data" "${menu_items["$index"]}"
		eval "$array_cmd"
		printf '[%s](%s)\n\n' "${data[1]}" "/${data[0]}/"
	done
}

generateLatest() {
	cat

	declare -A menu_items
	IFS="$DEFAULT_IFS"

	for post_path in src/content/posts/*.md; do
		post_properties="$(getPostProperties "$post_path")"
		post_id="$(basename "$post_path" | sed 's/.md//')"
		if [[ "$(getTextProperty "$post_properties" hideFromLatest)" != 'true' && "$(getTextProperty "$post_properties" language)" == "$LANGUAGE" && "$post_id" != "$POST_ID" ]]; then
			post_title="$(getTextProperty "$post_properties" title)"
			post_published_date="$(getTextProperty "$post_properties" publishedDate)"
			if [[ -z post_published_date ]]; then
				post_published_date="$post_id"
			fi
			data=("$post_id" "$post_title")
			printf -v data_str '%q ' "${data[@]}"
			menu_items["$post_published_date"]="$data_str"
		fi
	done

	mapfile -d '' sorted_menu_indexes < <(printf '%s\0' "${!menu_items[@]}" | sort -r -z)

	$1
	if [[ ${#menu_items[@]} != 0 ]]; then
		echo "##" "$TRANSLATION_LATEST"
	fi
	for index in "${sorted_menu_indexes[@]}"; do
		printf -v array_cmd "%q=( %s )" "data" "${menu_items["$index"]}"
		eval "$array_cmd"
		printf '[%s %s](%s)\n\n' "$index" "${data[1]}" "/${data[0]}/"
	done
}

replaceWithCommandOutput() {
	has_executed_additional_command=false
	while IFS= read -r line; do
		if [[ "$line" == *"$1"* ]]; then
			$2 $3 | xargs -0 -I INSERT -- $SHELL -c "echo '$line' | awk -v VAR='INSERT' '{ sub(/$1/, VAR); print; }'"
			has_executed_additional_command=true
		else
			echo "$line"
		fi
	done < /dev/stdin

	if [[ -v 3 && $has_executed_additional_command == false ]]; then
		$3
	fi
}

generateMeainMenuWithSeparator() {
	printf '\n---\n'
	generateMainMenu
}

set +H # Turn off history substitution to allow using !- in a string

sed 's/](..\/..\/assets/](\/assets/g' "$MARKDOWN_POST" \
	| generateLatest generateFooter \
	| replaceWithCommandOutput '<!--gopher-main-menu-->' generateMainMenu generateMeainMenuWithSeparator \
	| md2gemini/bin/md2gemini -l paragraph -f -a -p \
	| generateHeader \
	| tee -a "$1/index.gmi" \
	| gemtext2gophermap $1
