#!/bin/bash

## Authors:
##   Ajrat Makhmutov <rauty@altlinux.org>
##
## Copyright (C) 2024-2025  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"

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

	"$action" || return 1

	echo "action end: $action"
)

ACTIONS+=( create_razlivochniy_obraz )
create_razlivochniy_obraz() (
	alterator-mailbox-send-wrapper "step: check_parameters main_progress: 0"

	rm -rf "$in_workdir"
	mkdir -pv "$in_workdir/image/Metadata"
	cd "$in_workdir" || return 1

	if [ -n "$in_workdir" ] && test_bool "$in_compress_copied"; then
		run_step_ui_wrapper prepare_workdir                1  || return 1
		run_step_ui_wrapper create_copied_fs               25 || return 1
		run_step_ui_wrapper create_disk_partition_info     57 || return 1
		run_step_ui_wrapper create_install_scripts         58 || return 1
		run_step_ui_wrapper save_ready_to_use_image        59 || return 1
		run_step_ui_wrapper create_razlivochniy_mountpoint 60 || return 1
		run_step_ui_wrapper use_ready_to_use_image         80 || return 1
		run_step_ui_wrapper install_grub                   90 || return 1
		run_step_ui_wrapper umount_razlivochniy            99 || return 1
	elif { [ -n "$in_workdir" ] && ! test_bool "$in_compress_copied"; } || [ -n "$in_exdrive" ]; then
		run_step_ui_wrapper create_razlivochniy_mountpoint 1  || return 1
		run_step_ui_wrapper prepare_workdir                20 || return 1
		run_step_ui_wrapper create_copied_fs               40 || return 1
		run_step_ui_wrapper create_disk_partition_info     80 || return 1
		run_step_ui_wrapper create_install_scripts         81 || return 1
		run_step_ui_wrapper install_grub                   82 || return 1
		run_step_ui_wrapper umount_razlivochniy            95 || 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 [ -n "$create_razlivochniy_obraz_pid" ] && kill -0 "$create_razlivochniy_obraz_pid"; then
		echo "Terminating create_razlivochniy_obraz_pid $create_razlivochniy_obraz_pid"
		pstree "$create_razlivochniy_obraz_pid"
		if [ "$(ps -o cmd --no-headers fp "$create_razlivochniy_obraz_pid")" != '/bin/bash /usr/lib/alterator/backend3/kopidel' ]; then
			echo "terminate_creating_razlivochniy_obraz: CRITICAL ERROR: TRIED TO KILL NOT KOPIDEL CMD: $(ps -o cmd --no-headers fp "$create_razlivochniy_obraz_pid")"
			return 1
		fi
		echo "Terminating create_razlivochniy_obraz_pid $create_razlivochniy_obraz_pid"
		kill -- "-$create_razlivochniy_obraz_pid"
		sleep 0.5
		if kill -0 "$create_razlivochniy_obraz_pid" 2>/dev/null; then
			echo "Process $create_razlivochniy_obraz_pid ignored SIGTERM"
		fi
		create_razlivochniy_obraz_pid=""
		run_step umount_razlivochniy
	fi
)

ACTIONS+=( workdirs_list )
workdirs_list() (
	if ! "$KOPIDEL_LIBEXECDIR/update-ignored-files.sh" "$in_ignored_files"; then
		write_enum_item "" "$(_ "An unreadable custom list of ignored files is specified")"
		return 0
	fi

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

	output="$("$KOPIDEL_LIBEXECDIR/workdirs-list.sh" "$compress_copied_option")"
	status="$?"
	if [ "$status" -ne 0 ]; then
		FAULT_MSG="$(_ "There are no partitions available with enough free space. Required space:") $output."
		if test_bool "$in_async"; then
			echo "workdirs: ${WORKDIRS[*]}"
			alterator-mailbox-send-wrapper "target_list_updated: workdirs /kopidel name \"no_available\" label \"$FAULT_MSG\""
		else
			write_enum_item "no_available" "$FAULT_MSG"
		fi
		return 1
	fi

	WORKDIRS=()
	while IFS= read -r line; do
		workdir="$( echo "$line" | cut -d ' ' -f 1)"
		source="$(  echo "$line" | cut -d ' ' -f 2)"

		if test_bool "$in_async"; then
			WORKDIRS+=( name "\"$workdir\"" label "\"$(write_string "$workdir $(_ "in partition") $source")\"" )
		else
			write_enum_item "$workdir" "$workdir $(_ "in partition") $source"
		fi
	done <<< "$output"

	if test_bool "$in_async"; then
		echo "workdirs: ${WORKDIRS[*]}"
		alterator-mailbox-send-wrapper "target_list_updated: workdirs /kopidel ${WORKDIRS[*]}"
	fi
)

ACTIONS+=( exdrives_list )
exdrives_list() (
	if ! "$KOPIDEL_LIBEXECDIR/update-ignored-files.sh" "$in_ignored_files"; then
		write_enum_item "" "$(_ "An unreadable custom list of ignored files is specified")"
		return 0
	fi

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

	output="$("$KOPIDEL_LIBEXECDIR/exdrives-list.sh" "$compress_copied_option")"
	status="$?"
	if [ "$status" -ne 0 ]; then
		FAULT_MSG="$(_ "There are no external drives available with enough space. Required space:") $output."
		if test_bool "$in_async"; then
			echo "workdirs: ${WORKDIRS[*]}"
			alterator-mailbox-send-wrapper "target_list_updated: exdrives /kopidel name \"no_available\" label \"$FAULT_MSG\""
		else
			write_enum_item "no_available" "$FAULT_MSG"
		fi
		return 1
	fi

	EXDRIVES=()
	while IFS= read -r line; do
		name="$(      echo "$line" | cut -d ' ' -f 1 | sed 's/\\x20/ /g')"
		vendor="$(    echo "$line" | cut -d ' ' -f 2 | sed 's/\\x20/ /g')"
		model="$(     echo "$line" | cut -d ' ' -f 3 | sed 's/\\x20/ /g')"
		human_size="$(echo "$line" | cut -d ' ' -f 4 | sed 's/\\x20/ /g')"

		if test_bool "$in_async"; then
			EXDRIVES+=( name "\"$name\"" label "\"$vendor $model $human_size [$name]\"" )
		else
			write_enum_item "$name" "$vendor $model $human_size [$name]"
		fi
	done <<< "$output"

	if test_bool "$in_async"; then
		echo "exdrives: ${EXDRIVES[*]}"
		alterator-mailbox-send-wrapper "target_list_updated: exdrives /kopidel ${EXDRIVES[*]}"
	fi
)

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 "$KOPIDEL_LIBEXECDIR/update-ignored-files.sh" "$in_ignored_files"; then
		write_bool_param result true
	else
		write_bool_param result false
	fi
)

ACTIONS+=( get_color_from_text )
get_color_from_text() (
	color=$(echo "$in_text" \
		| grep -o -E 'color:\s*[^;]+' \
		| sed -n 's/color:\s*//p' \
		| sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' \
		| head -n1)

	if [[ -z "$color" ]]; then
		write_string_param color 'default'
	else
		write_string_param color "$color"
	fi
)

ACTIONS+=( is_obraz_building )
is_obraz_building() (
	if [ -n "$create_razlivochniy_obraz_pid" ] && kill -0 "$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 [ -n "$workdirs_list_pid" ] && kill -0 "$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 [ -n "$exdrives_list_pid" ] && kill -0 "$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() (
	workdir_mountpoint="$(realpath "$in_workdir" | sed "s/$WORKDIR_NAME\$//")"
	if "$KOPIDEL_LIBEXECDIR/check-fs-features.sh" "$workdir_mountpoint"; 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"
			pid_value="${!pid_var_name}"
			if [ -z "$pid_value" ] || ! kill -0 "$pid_value"; then
				original_monitor_state=""
				if [[ $- == *m* ]]; then
					original_monitor_state="enabled"
				else
					original_monitor_state="disabled"
				fi
				set -m

				run_action "$in_action" &
				declare -g "$pid_var_name=$!"

				if [ "$original_monitor_state" == "disabled" ]; then
					set +m
				fi

				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
