#!/bin/bash

## Authors:
##   Ajrat Makhmutov <rauty@altlinux.org>
##
## Copyright (C) 2024-2026  Basealt LLC
##
## This file is part of alterator-kopidel.
##
## alterator-kopidel is free software: you can redistribute it and/or modify it under the terms
## of the GNU General Public License as published by the Free Software Foundation,
## either version 3 of the License, or (at your option) any later version.
##
## alterator-kopidel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
## without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with alterator-kopidel.
## If not, see <https://www.gnu.org/licenses/>.

. alterator-sh-functions

if [ "$(id -u)" -ne 0 ]; then
	echo "$(_ "Please run the kopidel as root")." >&2
	exit 1
fi

. "${KOPIDEL_LIBDIR:-/usr/lib/alterator-kopidel}/steps"
. "$KOPIDEL_LIBDIR/process-group"
. "$KOPIDEL_LIBDIR/progress-bars"

while [[ $# -gt 0 ]]; do case "$1" in
	-X | --ignored-from)
		in_ignored_files="$2"
		shift 2
	;;
	--xz)
		in_compress_copied='#t'
		compress_copied_option='--xz'
		shift
	;;
	-O | --oem-mode)
		in_oem_mode='#t'
		shift
	;;
	--grub-efi-removable)
		in_grub_efi_removable='#t'
		shift
	;;
	--list-workdirs)
		only_print_workdirs="#t"
		shift
	;;
	--list-exdrives)
		only_print_exdrives="#t"
		shift
	;;
	-v | --version)
		rpm -q alterator-kopidel --qf "%{version}\n"
		exit 0
	;;
	-s | --step)
		step="$2"
		shift 2
	;;
	-h | --help)
		echo "$(_ 'Creates a "razlivochniy obraz".')"
		echo "$(_ "Usage:")"
		echo "$(_ "kopidel [Options] workdir")"
		echo "$(_ "kopidel [Options] /dev/external_drive")"
		echo
		echo "$(_ '"Workdir" is the path to the working directory where razlivochniy.img is created.')"
		echo "$(_ 'Please check that there is enough disk space available.')"
		echo "$(_ "The workdir name should be alterator-kopidel-workdir.")"
		echo
		echo "$(_ "Options:")"
		echo "	-X, --ignored-from   $(_ "The path to the file with the list of ignored files")."
		echo "	--xz                 $(_ "Compress the copied file system using xz")."
		echo "	-O, --oem-mode       $(_ "Installation in OEM mode")."
		echo "	-h, --help           $(_ "Display this message")."
		echo "	-v, --version        $(_ "Print version info and exit")."
		echo "	-s, --step           $(_ "Run a specific step instead of all of them (this is for testing only)")."
		echo "	--list-workdirs      $(_ "Display a list of possible working directories and exit")."
		echo "	--list-exdrives      $(_ "Display a list of possible external drives and exit")."
		if is_img_efi_bootable; then
		echo "	--grub-efi-removable $(_ "Install GRUB with the --removable flag")."
		fi
		echo
		echo "$(_ "Please report any problems to <https://bugzilla.altlinux.org/>")"
		exit 0
	;;
	' ' | '' ) shift ;;
	-* | --*)
		echo "$(_ "Unknown option:") $1" >&2
		exit 1
	;;
	*)
		workdir_or_exdrive="$1"
		shift
	;;
esac; done

if [ -z "$workdir_or_exdrive" ] && ! test_bool "$only_print_workdirs" && ! test_bool "$only_print_exdrives"; then
	echo "$(_ "ERROR: the working directory or external drive is not specified.")" >&2
	exit 1
fi

if [[ "$workdir_or_exdrive" == /dev/* ]]; then
	in_exdrive="$workdir_or_exdrive"
else
	in_workdir="$workdir_or_exdrive"
fi

if ! ignored_files_reason="$("$KOPIDEL_LIBEXECDIR/update-ignored-files.sh" "$in_ignored_files" 2>&1 1>/dev/null)"; then
	echo "$(_ "The custom list of ignored files is not usable:")" >&2
	echo "$ignored_files_reason" | tail -n1 >&2
	exit 1
fi

if [ -n "$in_workdir" ] || test_bool "$only_print_workdirs"; then
	if ! output="$("$KOPIDEL_LIBEXECDIR/workdirs-list.sh" "$compress_copied_option" 2>/dev/null)"; then
		echo "$(_ "There are no partitions available with enough free space. Required space:") $output." >&2
		exit 1
	fi

	if test_bool "$only_print_workdirs"; then
		echo "$(_ "List of possible working directories:")"
		echo "$output"
		exit 0
	fi

	if ! echo "$output" | grep -q "^$(realpath "$in_workdir") "; then
		echo "$(_ "ERROR: The working directory is not in the list of possible directories:")" >&2
		echo "$output" >&2
		exit 1
	fi
fi

if [ -n "$in_exdrive" ] || test_bool "$only_print_exdrives"; then
	if ! output="$("$KOPIDEL_LIBEXECDIR/exdrives-list.sh" "$compress_copied_option" 2>/dev/null)"; then
		echo "$(_ "There are no external drives available with enough space. Required space:") $output." >&2
		exit 1
	fi

	if test_bool "$only_print_exdrives"; then
		echo "$(_ "List of possible external drives:")"
		echo "$output"
		exit 0
	fi

	if ! echo "$output" | grep -q "^$(realpath "$in_exdrive") "; then
		echo "$(_ "ERROR: The external drive is not in the list of possible devices:")" >&2
		echo "$output" >&2
		exit 1
	fi
fi

if ! "$KOPIDEL_LIBEXECDIR/check-build-environment.sh"; then
	echo "$(_ "ERROR: the razlivochniy image cannot be created in the current environment.")" >&2
	exit 1
fi

step_num=0
step_count=1
run_step_cli_wrapper_bar() {
	(( step_num+=1 ))
	echo "[$(date)] $(_ "Step") $step_num/$step_count: ${STEPS["$1"]}."
	if progress_bar_is_drawable; then
		run_step "$1" | draw_progress_bar_handler
		rtrn="${PIPESTATUS[0]}"
		echo
	else
		run_step "$1" | draw_plain_progress_bar_handler
		rtrn="${PIPESTATUS[0]}"
	fi
	return "$rtrn"
}

run_build_plan() (
	mapfile -t plan < <(build_plan)
	step_count="${#plan[@]}"
	for entry in "${plan[@]}"; do
		run_step_cli_wrapper_bar "${entry%% *}" || return 1
	done
)

create_razlivochniy_obraz_pid=""
terminate_creating_razlivochniy_obraz() (
	echo ""

	if is_process_running "$create_razlivochniy_obraz_pid"; then
		echo "[$(date)] $(_ "User requested termination of the creation of the razlivochniy image")." >&2
		terminate_process_group "$create_razlivochniy_obraz_pid"
		case "$?" in
		0) echo "[$(date)] $(_ "The creation of the razlivochniy image has been successfully terminated")." >&2 ;;
		1) return 1 ;;
		esac
	fi
	run_step umount_razlivochniy >/dev/null
	exit 1
)

if progress_bar_is_drawable; then
	trap "tput cnorm" EXIT
	tput civis
fi
trap "terminate_creating_razlivochniy_obraz" INT TERM

if ! take_build_lock; then
	echo "$(_ "ERROR: another razlivochniy image is being built.")" >&2
	exit 1
fi

if [ -n "$step" ]; then
	if [[ -v STEPS["$step"] ]] || [[ "$KOPIDEL_DEBUG" == 1 && " ${SUBSTEPS[*]} " =~ " $step " ]]; then
		if ! run_step_cli_wrapper_bar "$step"; then
			echo "[$(date)] $(_ "Failed on the step:") $step." >&2
			echo "$(_ "See the build log:") ${in_workdir:-$EXDRIVE_WORKDIR}/build.log" >&2
			exit 1
		fi
		echo "[$(date)] $(_ "The step was completed successfully")."
	else
		echo "$(_ "There is no such step:")"" $step." >&2
		echo "$(_ "Steps list:")" "${!STEPS[@]}"
		if [ "$KOPIDEL_DEBUG" == 1 ]; then
			echo "$(_ "Substeps list:")"" ${SUBSTEPS[*]}."
		fi
		exit 1
	fi
else
	spawn_process_group run_build_plan
	create_razlivochniy_obraz_pid="$!"

	if wait "$create_razlivochniy_obraz_pid"; then
		echo "[$(date)] $(_ "Successfully created a razlivochniy image")."
	else
		run_step umount_razlivochniy > /dev/null

		echo "[$(date)] $(_ "Failed to create a razlivochniy image")." >&2
		echo "$(_ "See the build log:") ${in_workdir:-$EXDRIVE_WORKDIR}/build.log" >&2
		exit 1
	fi
fi
