#!/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_api_version=1
. alterator-sh-functions

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

ACTIONS=()
run_action() (
	action="$1"
	echo "action start: $action"

	"$action" || return 1

	echo "action end: $action"
)

declare -A ACTION_PIDS=()

is_action_running() (
	is_process_running "${ACTION_PIDS["$1"]-}"
)

is_chosen_target() (
	target="$1"
	[ -n "$target" ] && [ "$target" != "$EMPTY_LIST_PLACEHOLDER" ]
)

has_chosen_target() (
	is_chosen_target "$in_workdir" || is_chosen_target "$in_exdrive"
)

run_step_ui_wrapper() (
	alterator_mailbox_send_wrapper "step: $1 main_progress: $2"
	run_step "$1" | step_percentage_mailbox_sender
	if [ "${PIPESTATUS[0]}" -ne 0 ]; then
		echo "Failed on the step $1"
		send_build_error "$(_ "Failed on the step:") ${STEPS["$1"]}. $(_ "See the build log:") $(build_workdir)/build.log"
		return 1
	fi
)

ACTIONS+=( create_razlivochniy_obraz )
create_razlivochniy_obraz() (
	alterator_mailbox_send_wrapper "step: check_parameters main_progress: 0"

	if ! has_chosen_target; then
		no_target_msg="$(_ "No working directory or external drive is chosen.")"
		echo "create_razlivochniy_obraz: $no_target_msg"
		send_build_error "$no_target_msg"
		return 1
	fi

	if ! check_output="$("$KOPIDEL_LIBEXECDIR/check-build-environment.sh" 2>&1)"; then
		echo "$check_output"
		send_build_error "$check_output"
		return 1
	fi

	if ! take_build_lock "$(build_workdir)"; then
		send_build_error "$(_ "ERROR: another razlivochniy image is being built.")"
		return 1
	fi

	if ! reason="$(prepare_build_workdir 2>&1 >/dev/null)"; then
		echo "$reason"
		send_build_error "$(_ "Failed to prepare the working directory:") $(build_workdir). $reason"
		return 1
	fi

	run_build_plan run_step_ui_wrapper || return 1

	alterator_mailbox_send_wrapper "step: done main_progress: 100"
)

ACTIONS+=( terminate_creating_razlivochniy_obraz )
terminate_creating_razlivochniy_obraz() (
	build_pid="${ACTION_PIDS[create_razlivochniy_obraz]-}"
	echo "terminate_creating_razlivochniy_obraz: $build_pid"
	if is_process_running "$build_pid"; then
		terminate_process_group "$build_pid" || return 1
		run_step umount_razlivochniy
	fi
)

report_empty_target_list() (
	if test_bool "$in_async"; then
		alterator_mailbox_send_wrapper "target_list_updated: $1 /kopidel name \"$EMPTY_LIST_PLACEHOLDER\" label \"$(write_string "$2")\""
	else
		write_enum_item "$EMPTY_LIST_PLACEHOLDER" "$2"
	fi
)

answer_target_list() (
	kind="$1"
	lister="$2"
	no_targets_msg="$3"
	item_of_line="$4"

	KOPIDEL_IGNORED_FILES="$(mktemp -t kopidel-ignored-files.XXXXXX)"
	export KOPIDEL_IGNORED_FILES
	trap 'rm -f "$KOPIDEL_IGNORED_FILES"' EXIT

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

	if test_bool "$in_compress_copied"; then
		compress_copied_option="--xz"
	fi

	if ! output="$("$KOPIDEL_LIBEXECDIR/$lister" "$compress_copied_option")"; then
		report_empty_target_list "$kind" "$no_targets_msg $output."
		return 1
	fi

	items=()
	while IFS= read -r line; do
		mapfile -t item < <("$item_of_line" "$line")
		if test_bool "$in_async"; then
			items+=( name "\"$(write_string "${item[0]}")\"" label "\"$(write_string "${item[1]}")\"" )
		else
			write_enum_item "${item[0]}" "${item[1]}"
		fi
	done <<< "$output"

	if test_bool "$in_async"; then
		echo "$kind: ${items[*]}"
		alterator_mailbox_send_wrapper "target_list_updated: $kind /kopidel ${items[*]}"
	fi
)

workdir_item() (
	workdir="$(echo "$1" | cut -d ' ' -f 1)"
	source="$( echo "$1" | cut -d ' ' -f 2)"
	echo "$workdir"
	echo "$workdir $(_ "in partition") $source"
)

ACTIONS+=( workdirs_list )
workdirs_list() (
	answer_target_list workdirs workdirs-list.sh \
		"$(_ "There are no partitions available with enough free space. Required space:")" \
		workdir_item
)

exdrive_item() (
	name="${1%% *}"
	echo "$name"
	echo "${1#* } [$name]"
)

ACTIONS+=( exdrives_list )
exdrives_list() (
	answer_target_list exdrives exdrives-list.sh \
		"$(_ "There are no external drives available with enough space. Required space:")" \
		exdrive_item
)

ACTIONS+=( get_step_summary )
get_step_summary() (
	if [[ -v STEPS["$in_step"] ]]; then
		write_string_param step_summary "${STEPS["$in_step"]}"
	elif [ "$in_step" == "done" ]; then
		write_string_param step_summary "$(_ "Successfully created a razlivochniy obraz")"
	elif [ "$in_step" == "check_parameters" ]; then
		write_string_param step_summary "$(_ "Checking the parameters")"
	else
		write_error "Unknown step: $in_step."
		return 1
	fi
)

ACTIONS+=( check_ignored_files )
check_ignored_files() (
	if reason="$("$KOPIDEL_LIBEXECDIR/update-ignored-files.sh" --check "$in_ignored_files" 2>&1 1>/dev/null)"; then
		write_bool_param result true
	else
		write_bool_param result false
		write_string_param reason "$(echo "$reason" | tail -n1)"
	fi
)

write_bool_answer() (
	param="$1"
	shift
	if "$@"; then
		write_bool_param "$param" true
	else
		write_bool_param "$param" false
	fi
)

ACTIONS+=( is_obraz_building )
is_obraz_building() (
	write_bool_answer is_obraz_building is_action_running create_razlivochniy_obraz
)

ACTIONS+=( is_calculating_workdirs )
is_calculating_workdirs() (
	write_bool_answer is_calculating_workdirs is_action_running workdirs_list
)

ACTIONS+=( is_calculating_exdrives )
is_calculating_exdrives() (
	write_bool_answer is_calculating_exdrives is_action_running exdrives_list
)

ACTIONS+=( is_img_efi_bootable_backend )
is_img_efi_bootable_backend() (
	write_bool_answer is_img_efi_bootable_backend is_img_efi_bootable
)

ACTIONS+=( is_workdir_supports_copying )
is_workdir_supports_copying() (
	write_bool_answer is_workdir_supports_copying \
		"$KOPIDEL_LIBEXECDIR/check-fs-features.sh" "$(workdir_mountpoint "$in_workdir")"
)

on_message() {
	if [ -z "$in_action" ]; then
		return 0
	fi
	if [[ " ${ACTIONS[*]} " =~ " ${in_action} " ]]; then
		if test_bool "$in_async"; then
			if ! is_action_running "$in_action"; then
				spawn_process_group run_action "$in_action"
				ACTION_PIDS["$in_action"]="$!"

				echo "pid_value ${ACTION_PIDS["$in_action"]} in_action $in_action"
			fi
		else
			run_action "$in_action"
		fi
	else
		write_error "Unknown action: $in_action."
		return 1
	fi
}

message_loop on_message
