#!/bin/bash

set -euo pipefail

die() {
	echo "Error: $*" >&2
	exit 1
}

: "${RPM_MATRIX:?RPM_MATRIX is not set}"
: "${GITHUB_SHA:?GITHUB_SHA is not set}"
: "${RELEASE_OUTPUT_DIR:?RELEASE_OUTPUT_DIR is not set}"

readonly rpm_artifact_root="${RPM_ARTIFACT_ROOT:-package-artifacts/rpm}"
readonly deb_artifact_root="${DEB_ARTIFACT_ROOT:-package-artifacts/deb}"
readonly release_output_dir="${RELEASE_OUTPUT_DIR}"

[[ "${GITHUB_SHA}" =~ ^[0-9a-fA-F]{40,64}$ ]] ||
	die "GITHUB_SHA is not a full Git object ID."
jq -e '
	.include |
	type == "array" and length > 0 and
	all(.[];
		((.target | type) == "string" and (.target | length) > 0) and
		((.kernel_version | type) == "string" and
		 (.kernel_version | length) > 0))
' \
	<<<"${RPM_MATRIX}" >/dev/null || die "RPM_MATRIX is invalid."

mapfile -t rpm_targets < <(jq -r '.include[].target' <<<"${RPM_MATRIX}")
mapfile -t rpm_kernel_versions < <(
	jq -r '.include[].kernel_version' <<<"${RPM_MATRIX}"
)
[[ ${#rpm_targets[@]} -eq ${#rpm_kernel_versions[@]} ]] ||
	die "RPM_MATRIX contains invalid target or kernel version fields."

rpm_archive_kernel_versions=()
declare -A seen_targets=()
for index in "${!rpm_targets[@]}"; do
	target="${rpm_targets[index]}"
	kernel_version="${rpm_kernel_versions[index]}"
	[[ "${target}" =~ ^[a-z0-9][a-z0-9._-]*$ ]] ||
		die "Invalid RPM target: ${target}"
	[[ "${kernel_version}" =~ ^[A-Za-z0-9][A-Za-z0-9._+-]*$ ]] ||
		die "Invalid RPM kernel version: ${kernel_version}"
	[[ "${kernel_version}" =~ ^(.+)\.el[0-9]+(_[0-9]+|uek)?$ ]] ||
		die "Unsupported RPM kernel version: ${kernel_version}"
	rpm_archive_kernel_versions[index]="${BASH_REMATCH[1]}"
	[[ -z "${seen_targets[${target}]+present}" ]] ||
		die "Duplicate RPM target: ${target}"
	seen_targets["${target}"]=1
done

if [[ -e "${release_output_dir}" && ! -d "${release_output_dir}" ]]; then
	die "Release output path is not a directory: ${release_output_dir}"
fi
mkdir -p -- "${release_output_dir}"
if [[ -n "$(find "${release_output_dir}" -mindepth 1 -maxdepth 1 -print -quit)" ]]; then
	die "Release output directory is not empty: ${release_output_dir}"
fi

create_bundle() {
	local source_dir="$1"
	local bundle_name="$2"
	shift 2

	tar --sort=name --mtime='UTC 1970-01-01' \
		--owner=0 --group=0 --numeric-owner \
		-C "${source_dir}" -cf - "$@" |
		gzip -n >"${release_output_dir}/${bundle_name}"
	(
		cd "${release_output_dir}"
		sha256sum "${bundle_name}" >"${bundle_name}.sha256"
	)
}

for index in "${!rpm_targets[@]}"; do
	target="${rpm_targets[index]}"
	archive_kernel_version="${rpm_archive_kernel_versions[index]}"
	artifact_name="scst-rpm-${target}-x86_64-${GITHUB_SHA}"
	artifact_dir="${rpm_artifact_root}/${artifact_name}"
	[[ -d "${artifact_dir}/RPMS" ]] ||
		die "Missing RPMS directory in ${artifact_name}."
	[[ -d "${artifact_dir}/SRPMS" ]] ||
		die "Missing SRPMS directory in ${artifact_name}."
	[[ -f "${artifact_dir}/SHA256SUMS" ]] ||
		die "Missing SHA256SUMS in ${artifact_name}."
	[[ -n "$(find "${artifact_dir}/RPMS" -type f -name '*.rpm' -print -quit)" ]] ||
		die "No binary RPM packages found in ${artifact_name}."
	[[ -n "$(find "${artifact_dir}/SRPMS" -type f -name '*.rpm' -print -quit)" ]] ||
		die "No source RPM packages found in ${artifact_name}."
	(
		cd "${artifact_dir}"
		sha256sum --check SHA256SUMS
	) || die "RPM checksum verification failed for ${artifact_name}."

	create_bundle "${artifact_dir}" \
		"scst-master-${target}-kernel-${archive_kernel_version}-x86_64.tar.gz" \
		RPMS SRPMS SHA256SUMS
done

[[ -d "${deb_artifact_root}" ]] ||
	die "Missing DEB artifact root: ${deb_artifact_root}"

mapfile -d '' -t deb_artifact_dirs < <(
	find "${deb_artifact_root}" -mindepth 1 -maxdepth 1 -type d \
		-name "scst-deb-ubuntu-*-x86_64-${GITHUB_SHA}" -print0 |
		sort -z
)
[[ ${#deb_artifact_dirs[@]} -gt 0 ]] ||
	die "No Ubuntu DEB artifact directories found."

find_one_deb_file() {
	local artifact_dir="$1"
	local pattern="$2"
	local -a matches=()

	mapfile -d '' -t matches < <(
		find "${artifact_dir}" -maxdepth 1 -type f \
			-name "${pattern}" -print0
	)
	[[ ${#matches[@]} -eq 1 ]] ||
		die "Expected one DEB artifact matching ${pattern}, found ${#matches[@]}."
	deb_files+=("${matches[0]##*/}")
}

declare -A seen_ubuntu_releases=()
for artifact_dir in "${deb_artifact_dirs[@]}"; do
	artifact_name="${artifact_dir##*/}"
	ubuntu_release="${artifact_name#scst-deb-ubuntu-}"
	ubuntu_release="${ubuntu_release%-x86_64-"${GITHUB_SHA}"}"
	[[ "${ubuntu_release}" =~ ^[0-9]{2}\.04$ ]] ||
		die "Invalid Ubuntu release in artifact name: ${artifact_name}"
	[[ -z "${seen_ubuntu_releases[${ubuntu_release}]+present}" ]] ||
		die "Duplicate Ubuntu release: ${ubuntu_release}"
	seen_ubuntu_releases["${ubuntu_release}"]=1

	deb_files=()
	find_one_deb_file "${artifact_dir}" 'scst-dkms_*.deb'
	find_one_deb_file "${artifact_dir}" 'scstadmin_*.deb'
	find_one_deb_file "${artifact_dir}" 'iscsi-scst_*.deb'
	find_one_deb_file "${artifact_dir}" '*.dsc'
	find_one_deb_file "${artifact_dir}" '*.debian.tar.*'
	find_one_deb_file "${artifact_dir}" '*.orig.tar.*'

	mapfile -d '' -t all_deb_packages < <(
		find "${artifact_dir}" -maxdepth 1 -type f -name '*.deb' -print0
	)
	[[ ${#all_deb_packages[@]} -eq 3 ]] ||
		die "Expected exactly three binary DEB packages in ${artifact_name}, found ${#all_deb_packages[@]}."

	create_bundle "${artifact_dir}" \
		"scst-master-ubuntu-${ubuntu_release}-x86_64.tar.gz" \
		"${deb_files[@]}"
done

expected_files="$(((${#rpm_targets[@]} + ${#deb_artifact_dirs[@]}) * 2))"
actual_files="$(find "${release_output_dir}" -maxdepth 1 -type f |
	wc -l)"
[[ "${actual_files}" -eq "${expected_files}" ]] ||
	die "Expected ${expected_files} release assets, found ${actual_files}."
