#!/usr/bin/env bash
. /lib/gentoo/functions.sh || { echo "Failed to source functions.sh!" ; exit 1 ; }
. "$(pkg-config iwdevtools --variable=atomf)" || { echo "Failed to source iwdevtools' atomf!" ; exit 1 ; }

# Wrapper function to handle environment preservation for both sudo and doas (but mostly doas)
run_elevated() {
	# Collect environment variables that need to be preserved
	local env_vars=()

	# Core Portage variables
	[[ -n "$PORTAGE_TMPDIR" ]] && env_vars+=("PORTAGE_TMPDIR=$PORTAGE_TMPDIR")
	[[ -n "$PORTAGE_USERNAME" ]] && env_vars+=("PORTAGE_USERNAME=$PORTAGE_USERNAME")
	[[ -n "$PORTAGE_WORKDIR_MODE" ]] && env_vars+=("PORTAGE_WORKDIR_MODE=$PORTAGE_WORKDIR_MODE")
	[[ -n "$PORTAGE_COMPRESS_EXCLUDE_SUFFIXES" ]] && env_vars+=("PORTAGE_COMPRESS_EXCLUDE_SUFFIXES=$PORTAGE_COMPRESS_EXCLUDE_SUFFIXES")

	# Build-related variables
	[[ -n "$ABI_X86" ]] && env_vars+=("ABI_X86=$ABI_X86")
	[[ -n "$MAKEOPTS" ]] && env_vars+=("MAKEOPTS=$MAKEOPTS")
	[[ -n "$EMERGE_DEFAULT_OPTS" ]] && env_vars+=("EMERGE_DEFAULT_OPTS=$EMERGE_DEFAULT_OPTS")

	# Package-specific DOCS_PREBUILT variables (dynamically detect them)
	local var
	for var in $(compgen -v | grep '_DOCS_PREBUILT$'); do
		[[ -n "${!var}" ]] && env_vars+=("$var=${!var}")
	done

	# MY_DOCS_PREBUILT if set
	[[ -n "$MY_DOCS_PREBUILT" ]] && env_vars+=("MY_DOCS_PREBUILT=$MY_DOCS_PREBUILT")

	# Language/locale settings
	[[ -n "$LC_ALL" ]] && env_vars+=("LC_ALL=$LC_ALL")
	[[ -n "$LANG" ]] && env_vars+=("LANG=$LANG")

	# If using doas, we need to explicitly pass all environment variables
	# If using sudo, it preserves environment by default with -E, but we'll be explicit since we had to do the work for doas anyway
	if [[ "$ELEVATE_CMD" == "sudo" || "$ELEVATE_CMD" == "doas" ]]; then
		"$ELEVATE_CMD" env "${env_vars[@]}" "$@"
	else
		eerror "Unknown elevation command: $ELEVATE_CMD"
		exit 1
	fi
}

# Helper function to run ebuild commands with all necessary environment variables
run_ebuild_with_env() {
	local env_vars=()

	# Build core environment array
	env_vars+=("FEATURES=-test")
	env_vars+=("USE=doc man")
	[[ -n "$PORTAGE_TMPDIR" ]] && env_vars+=("PORTAGE_TMPDIR=$PORTAGE_TMPDIR")
	[[ -n "$PORTAGE_USERNAME" ]] && env_vars+=("PORTAGE_USERNAME=$PORTAGE_USERNAME")
	[[ -n "$PORTAGE_WORKDIR_MODE" ]] && env_vars+=("PORTAGE_WORKDIR_MODE=$PORTAGE_WORKDIR_MODE")
	[[ -n "$PORTAGE_COMPRESS_EXCLUDE_SUFFIXES" ]] && env_vars+=("PORTAGE_COMPRESS_EXCLUDE_SUFFIXES=$PORTAGE_COMPRESS_EXCLUDE_SUFFIXES")

	# Include package-specific DOCS_PREBUILT variables
	local var
	for var in $(compgen -v | grep '_DOCS_PREBUILT$'); do
		[[ -n "${!var}" ]] && env_vars+=("$var=${!var}")
	done
	[[ -n "$MY_DOCS_PREBUILT" ]] && env_vars+=("MY_DOCS_PREBUILT=$MY_DOCS_PREBUILT")

	# Debug: Show what environment variables we're setting
	veinfo "Debug: run_ebuild_with_env environment variables:"
	local env_var
	for env_var in "${env_vars[@]}"; do
		veinfo "  $env_var"
	done

	# Run the ebuild command
	env "${env_vars[@]}" ebuild "$@"
}

generate-docs_setup_environment() {

	atomset ${1} || atomset ${PWD}/${1} || { eerror "Failed to run: 'atomset ${1}'. Exiting!" ; exit 1 ; }

	# We don't want to compress the man pages ourselves
	export PORTAGE_COMPRESS_EXCLUDE_SUFFIXES=".*"
	export PORTAGE_TMPDIR=${PORTAGE_TMPDIR:-/tmp/${0##*/}}
	export PORTAGE_USERNAME="$(whoami)"
	export PORTAGE_WORKDIR_MODE="775"
	local mtime=${SOURCE_DATE_EPOCH:-1970-01-01}
	if [[ ${mtime} =~ ^[0-9]+$ ]] ; then
		mtime="@${mtime}"
	fi
	# Make reproducible tarballs. Clobber timestamps, sort files, and set ownership.
	export REPRODUCIBLE_TAR_ARGS=(
		"--mtime=${mtime}"
		"--sort=name"
		"--owner=portage"
		"--group=portage"
	)
	export XZ_DEFAULTS="-9 -T 0"

	if [[ ${PWD} == */${CATEGORY}/${PN} ]] ; then
		# If we're already in the directory with the ebuilds,
		# we can back up instead.
		local repo_path=${PWD}/../..
	else
		local repo_path=${PWD}
	fi

	# Clean up tmpdir if it exists; create it if it doesn't.
	if [[ -d "${PORTAGE_TMPDIR}" ]] ; then
		rm -rf "${PORTAGE_TMPDIR}"/portage/${CATEGORY}/${PN} || { eerror "Failed to clean up ${PORTAGE_TMPDIR}/portage/${CATEGORY}/${PN}. Exiting!" ; exit 1 ; }
	fi
	mkdir -p "${PORTAGE_TMPDIR}"/portage/${CATEGORY}/${PN} || { eerror "Failed to create ${PORTAGE_TMPDIR}/portage/${CATEGORY}/${PN}. Exiting!" ; exit 1 ; }

	# We can't guarantee that sudo is installed; but if we find it prefer sudo.
	if command -v sudo >/dev/null 2>&1; then
		ELEVATE_CMD="sudo"
	elif command -v doas >/dev/null 2>&1; then
		ELEVATE_CMD="doas"
	else
		echo "Error: Neither sudo nor doas is available."
		exit 1
	fi

	# For new setups (first-time running doc generation at all), not
	# all the infrastructure may be in the ebuild yet. We only pass
	# USE="doc man" ... when it's not present because otherwise
	# it pulls in unnecessary deps. We can just rely on the deps
	# from ${PN^^}_DOCS_PREBUILT=0 when it's an already setup package.
	local docs_prebuilt_set="${PN^^}_DOCS_PREBUILT"
	local use_prefix=()
	if [[ -n "${!docs_prebuilt_set}" ]] || [[ -n "${MY_DOCS_PREBUILT}" ]] ; then
		use_prefix=( env USE='doc man' )
	fi

	# Debug: Show the variable name and its value
	veinfo "Debug: PN='${PN}'"
	veinfo "Debug: docs_prebuilt_set variable name='${docs_prebuilt_set}'"
	veinfo "Debug: ${docs_prebuilt_set} value='${!docs_prebuilt_set}'"
	veinfo "Debug: MY_DOCS_PREBUILT value='${MY_DOCS_PREBUILT}'"


	# Clean up any existing docs tarball entries for this specific version before regenerating manifest
	# This is important because we might have fetched a 404 page or corrupt file previously,
	# Since we make reproducible tarballs anyway, our worst case here is ending up in the same state.
	local manifest_file="${repo_path}/${CATEGORY}/${PN}/Manifest"
	if [[ -f "$manifest_file" ]]; then
		einfo "Cleaning existing ${P}-docs.tar.xz entries from Manifest"
		# Remove lines containing this specific version's docs tarball
		sed -i "/${P}-docs\.tar\.xz/d" "$manifest_file" || true
	fi

	# Remove docs tarball from distfiles if it exists
	local docs_tarball="/var/cache/distfiles/${P}-docs.tar.xz"
	if [[ -f "$docs_tarball" ]]; then
		einfo "Removing existing docs tarball: $docs_tarball"
		rm -f "$docs_tarball" || true
	fi

	run_elevated "${use_prefix[@]}" env FEATURES="-test" env PORTDIR_OVERLAY="${repo_path}" emerge --quiet --oneshot --onlydeps =${PF} || { eerror "Installing doc dependencies for =${PF} failed! Exiting!" ; exit 1 ; }

	# We need this to flush out a previous doc entry from a failed attempt
	# `pkgdev` isn't suitable here because it will just fetch the docs tarball regardless of PN_DOCS_PREBUILT.
	run_ebuild_with_env "${repo_path}/${1}" manifest || { eerror "Failed to update Manifest" ; exit 1 ; }
	run_ebuild_with_env "${repo_path}/${1}" clean compile install || { eerror "Failed to build ${1} with USE='doc man'. Exiting!" ; exit 1 ; }

	D="${PORTAGE_TMPDIR}"/portage/${CATEGORY}/${PF}/image
	WORKDIR="${PORTAGE_TMPDIR}"/portage/${CATEGORY}/${PF}/work
	# Borrowed from mgorny-dev-tools' pkgdiff
	S=$(sed -nr 's/^declare -x S="(.*)"/\1/p' "${PORTAGE_TMPDIR}"/portage/${CATEGORY}/${PF}/temp/environment)

	dir=$(mktemp -d)
	mkdir "${dir}"/${P}-docs || { eerror "Creating ${dir}/${P}-docs failed. Exiting!" ; exit 1 ; }
}

generate-docs_copy_docs() {
	ebegin "Copying docs to ${dir}/${P}-docs"
	cp -r "${D}"/usr/share/man*/* "${dir}"/${P}-docs/
	eend ${?} || { eerror "Copying docs failed!" ; exit 1 ; }
}

generate-docs_create_tarball() {
	ebegin "Creating tarball"

	# Embed generate-docs.bashlib and the generate-${PN}-docs script
	# within the tarball for posterity.
	cp {${0},$(dirname ${BASH_SOURCE}/generate-docs.bashlib)} "${dir}"/${P}-docs/ || { eerror "Failed to embed script within tarball. Exiting!" ; exit 1 ; }

	# Set reproducible timestamps on embedded scripts to ensure consistent tarballs
	local touch_mtime=${SOURCE_DATE_EPOCH:-1970-01-01}
	if [[ ${touch_mtime} =~ ^[0-9]+$ ]] ; then
		touch_mtime="@${touch_mtime}"
	fi
	touch -d "${touch_mtime}" "${dir}"/${P}-docs/$(basename ${0}) "${dir}"/${P}-docs/generate-docs.bashlib

	tar "${REPRODUCIBLE_TAR_ARGS[@]}" -caf "${dir}"/${P}-docs.tar.xz -C "${dir}" ${P}-docs/
	eend ${?} || { eerror "Creating tarball failed!" ; exit 1 ; }

	einfo "Tarball at ${dir}/${P}-docs.tar.xz"
}

generate-docs() {
	generate-docs_setup_environment "$@"
	generate-docs_copy_docs "$@"
	generate-docs_create_tarball "$@"
}
