#!/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"
)

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:") ${in_workdir:-$EXDRIVE_WORKDIR}/build.log"
		return 1
	fi
)

create_razlivochniy_obraz::steps() (
	mapfile -t plan < <(build_plan)
	for entry in "${plan[@]}"; do
		read -r step main_progress <<< "$entry"
		run_step_ui_wrapper "$step" "$main_progress" || return 1
	done
)

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; then
		send_build_error "$(_ "ERROR: another razlivochniy image is being built.")"
		return 1
	fi

	run_step umount_razlivochniy > /dev/null

	if ! { rm -rf "$in_workdir" &&
		mkdir -pv "$in_workdir/image/Metadata" &&
		cd "$in_workdir"; }
	then
		send_build_error "$(_ "Failed to prepare the working directory:") $in_workdir."
		return 1
	fi

	if ! create_razlivochniy_obraz::steps; then
		run_step umount_razlivochniy > /dev/null
		return 1
	fi

	alterator_mailbox_send_wrapper "step: done main_progress: 100"
)

ACTIONS+=( terminate_creating_razlivochniy_obraz )
terminate_creating_razlivochniy_obraz() (
	echo "terminate_creating_razlivochniy_obraz: $create_razlivochniy_obraz_pid"
	if is_process_running "$create_razlivochniy_obraz_pid"; then
		terminate_process_group "$create_razlivochniy_obraz_pid"
		if [ "$?" -eq 1 ]; then
			return 1
		fi
		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 \"$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"

	if ! "$KOPIDEL_LIBEXECDIR/update-ignored-files.sh" "$in_ignored_files"; then
		report_empty_target_list "$kind" "$(_ "An unreadable custom list of ignored files is specified")"
		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 "\"${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_field() (
	echo "$1" | cut -d ' ' -f "$2" | sed 's/\\x20/ /g'
)

exdrive_item() (
	name="$(      exdrive_field "$1" 1)"
	vendor="$(    exdrive_field "$1" 2)"
	model="$(     exdrive_field "$1" 3)"
	human_size="$(exdrive_field "$1" 4)"
	echo "$name"
	echo "$vendor $model $human_size [$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
)

ACTIONS+=( is_obraz_building )
is_obraz_building() (
	if is_process_running "$create_razlivochniy_obraz_pid"; then
		write_bool_param is_obraz_building true
		echo "is_obraz_building: true"
	else
		echo "is_obraz_building: false create_razlivochniy_obraz_pid $create_razlivochniy_obraz_pid"
		write_bool_param is_obraz_building false
	fi
)
ACTIONS+=( is_calculating_workdirs )
is_calculating_workdirs() (
	if is_process_running "$workdirs_list_pid"; then
		write_bool_param is_calculating_workdirs true
		echo "is_calculating_workdirs: true"
	else
		write_bool_param is_calculating_workdirs false
	fi
)
ACTIONS+=( is_calculating_exdrives )
is_calculating_exdrives() (
	if is_process_running "$exdrives_list_pid"; then
		echo "is_calculating_exdrives: true"
		write_bool_param is_calculating_exdrives true
	else
		write_bool_param is_calculating_exdrives false
	fi
)
ACTIONS+=( is_img_efi_bootable_backend )
is_img_efi_bootable_backend() (
	if is_img_efi_bootable; then
		write_bool_param is_img_efi_bootable_backend true
	else
		write_bool_param is_img_efi_bootable_backend false
	fi
)
ACTIONS+=( is_workdir_supports_copying )
is_workdir_supports_copying() (
	if "$KOPIDEL_LIBEXECDIR/check-fs-features.sh" "$(workdir_mountpoint "$in_workdir")"; then
		write_bool_param is_workdir_supports_copying true
	else
		write_bool_param is_workdir_supports_copying false
	fi
)

on_message() {
	if [ -z "$in_action" ]; then
		return 0
	fi
	if [[ " ${ACTIONS[*]} " =~ " ${in_action} " ]]; then
		if test_bool "$in_async"; then
			pid_var_name="${in_action}_pid"
			if ! is_process_running "${!pid_var_name}"; then
				spawn_process_group run_action "$in_action"
				declare -g "$pid_var_name=$!"

				echo "pid_value ${!pid_var_name} pid_var_name $pid_var_name 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
