## 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/>.

if [ -n "${__included_kopidel_disk_profile-}" ]; then
	return 0
fi
readonly __included_kopidel_disk_profile=1

. "${KOPIDEL_LIBDIR:-/usr/lib/alterator-kopidel}/variables"

print_fstab_only_spaces() {
	sed -E -e 's/\t+/ /g' -e 's/ +/ /g' "$FSTAB"
}

fstab_unescape() (
	unescaped=
	rest="$1"
	while [[ "$rest" =~ \\([0-7]{3}) ]]; do
		unescaped+="${rest%%"${BASH_REMATCH[0]}"*}"
		printf -v char "\\${BASH_REMATCH[1]}"
		unescaped+="$char"
		rest="${rest#*"${BASH_REMATCH[0]}"}"
	done
	printf '%s' "$unescaped$rest"
)

scheme_string() (
	escaped="${1//\\/\\\\}"
	echo "\"${escaped//\"/\\\"}\""
)

create_disk_partition_info::fstab_subvolume_lines() (
	print_fstab_only_spaces | grep "^UUID=$1 .*[, ]subvol=/"
)

create_disk_partition_info::subvolumes_info_by_uuid() (
	UUID="${1:?}"
	result=

	result="$(create_disk_partition_info::fstab_subvolume_lines "$UUID" |
		while read -r line; do
			name="$(echo "$line" | sed -e 's@.*subvol=/@@' -e 's@[, ].*@@')"
			mountpoint="$(echo "$line" | cut -d ' ' -f 2)"

			if [[ -z "$name" || -z "$mountpoint" ]]; then
				continue
			fi
			echo -n " ($(scheme_string "$name") . $(scheme_string "$mountpoint"))"
		done)"

	if [ -n "$result" ]; then
		result="(subvols$result)"
	fi
	echo "$result"
)

create_disk_partition_info::lvm_info_by_uuid() (
	UUID="${1:?}"
	device= vg_name= lv_name= result=

	device="$(blkid -o device -t UUID="$UUID" 2>/dev/null)"
	if [ -z "$device" ]; then
		echo ""
		return
	fi

	vg_name="$(lvs --noheadings -o vg_name "$device" 2>/dev/null | tr -d ' ')"
	lv_name="$(lvs --noheadings -o lv_name "$device" 2>/dev/null | tr -d ' ')"

	if [ -n "$vg_name" ]; then
		result="(vg . \"$vg_name\")"
	fi
	if [ -n "$lv_name" ]; then
		[ -n "$result" ] && result+=" "
		result+="(lv . \"$lv_name\")"
	fi

	echo "$result"
)

create_disk_partition_info::min_size() (
	uuid="$1"
	max_size="$2"
	fsused="$3"
	shift 3

	min_size="$(du -bsc --exclude-from="$IGNORED_FILES" --exclude="$WORKDIR_NAME" "$@" 2>/dev/null | tail -n 1 | cut -f 1)"
	if [[ -z "$min_size" || "$min_size" == 0 ]]; then
		echo "WARNING: min_size of the partition with uuid $uuid is not calculated with du!" >&2
		(( min_size = max_size / 2 ))
	else
		(( min_size /= BYTES_IN_SECTOR ))
	fi

	if [[ -n "$fsused" && "$min_size" -gt "$(( fsused / BYTES_IN_SECTOR ))" ]]; then
		echo "WARNING: min_size $min_size greater than FSUSED $(( fsused / BYTES_IN_SECTOR )) of the partition with uuid $uuid!" >&2
		(( min_size = fsused / BYTES_IN_SECTOR ))
	fi

	if [ "$max_size" -lt "$min_size" ]; then
		echo "WARNING: max_size $max_size less than min_size $min_size of the partition with uuid $uuid!" >&2
		min_size="$max_size"
	fi
	echo "$min_size"
)

create_disk_partition_info::methods_field() (
	type="$1"
	uuid="$2"
	declare -A type_blkid_to_methods=( [part]="plain" [lvm]="lvm" )
	methods="${type_blkid_to_methods["$type"]}"

	lvm_info=""
	if [[ "$type" == "lvm" ]]; then
		lvm_info="$(create_disk_partition_info::lvm_info_by_uuid "$uuid")"
	fi

	if [ -n "$lvm_info" ]; then
		echo "(methods ($methods $lvm_info))"
	else
		echo "(methods $methods)"
	fi
)

create_disk_partition_info::profile_entry() (
	declare -A fsname_blkid_to_evms=( [ext4]="Ext4" [xfs]="XFS" [btrfs]="BtrFS" [vfat]="FAT32" [ntfs]="NTFS" [swap]="SWAPFS" )
	fstype="$(echo "$1" | cut -d ' ' -f 1)"
	size="$(  echo "$1" | cut -d ' ' -f 2)"
	uuid="$(  echo "$1" | cut -d ' ' -f 3)"
	type="$(  echo "$1" | cut -d ' ' -f 4)"
	fsused="$(echo "$1" | cut -d ' ' -f 5)"

	if [[ -z "$fstype" || -z "$size" || -z "$uuid" ]]; then
		return 1
	fi

	if [[ "$fstype" == "LVM2_member" || "$fstype" == "exfat" ]]; then
		return 1
	fi

	if ! [[ "$type" == part || "$type" == lvm ]]; then
		echo "Unknown TYPE: $type" >&2
		return 1
	fi

	evms_fstype="${fsname_blkid_to_evms["$fstype"]}"
	if [ -z "$evms_fstype" ]; then
		echo "Unknown FSTYPE: $fstype" >&2
		return 1
	fi

	mountpoint="$(print_fstab_only_spaces | grep "^UUID=$uuid " | grep -v "[, ]subvol=/" | head -n 1 | cut -d ' ' -f 2)"
	subvolumes="$(create_disk_partition_info::subvolumes_info_by_uuid "$uuid")"
	if [[ -z "$mountpoint" && -z "$subvolumes" ]]; then
		echo "Mountpoint of partition with uuid $uuid not found in $FSTAB!" >&2
		return 1
	fi

	paths=()
	if [ -n "$mountpoint" ]; then
		paths+=( "$(fstab_unescape "$mountpoint")" )
	fi
	if [ -n "$subvolumes" ]; then
		mapfile -t -O "${#paths[@]}" paths < <(create_disk_partition_info::fstab_subvolume_lines "$uuid" | cut -d ' ' -f 2 |
			while read -r subvolume_mountpoint; do
				fstab_unescape "$subvolume_mountpoint"
				echo
			done)
	fi

	(( max_size = size / BYTES_IN_SECTOR ))
	if [[ "$fstype" == swap || "$mountpoint" == /boot/efi ]]; then
		min_size="$max_size"
	else
		min_size="$(create_disk_partition_info::min_size "$uuid" "$max_size" "$fsused" "${paths[@]}")"
	fi

	echo "               ($(scheme_string "$mountpoint") (size $min_size . $max_size ) (fsim . \"$evms_fstype\") $(create_disk_partition_info::methods_field "$type" "$uuid") $subvolumes)"
)
