#!/bin/bash
# SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
#
# SPDX-License-Identifier: GPL-3.0-or-later

set -e
#set -x

readonly PREREQ=""

prereqs() {
	echo "${PREREQ}"
}

case "${1}" in
prereqs)
	prereqs
	exit 0
	;;
esac

# Global variables
tmp_fix_file=$(mktemp /tmp/deepin-fix-init-install-XXXXXXXX.log)
tmp_config_file=$(mktemp /tmp/deepin-fix-init-cfg-XXXXXXXX)

. /usr/share/initramfs-tools/hook-functions

# ========================
# Function Definitions
# ========================

log_info() {
    echo "[INFO] $*"
}

log_warn() {
    echo "[WARN] $*" >&2
}

log_error() {
    echo "[ERROR] $*" >&2
}

# Copy executable file into initramfs
copy_exec_wrapper() {
    local src="$1"
    local dest="$2"
    copy_exec "$src" "$dest" || {
        log_warn "Failed to copy executable: $src -> $dest"
        echo "not copy_exec $src" >> "$tmp_fix_file"
    }
}

# Wrapper for copy_file to support 1 or 2 arguments
# Usage:
#   copy_file_wrapper <source> [<destination>]
copy_file_wrapper() {
    local src="$1"
    local dest="$2"

    if [ -z "$dest" ]; then
        # Only one argument provided, pass it directly to copy_file
        copy_file file "$src" || {
            log_warn "Failed to copy file: $src"
            echo "not install $src" >> "$tmp_fix_file"
        }
    else
        # Two arguments provided, specify both source and destination
        copy_file file "$src" "$dest" || {
            log_warn "Failed to copy file: $src -> $dest"
            echo "not install $src" >> "$tmp_fix_file"
        }
    fi
}

# Check if running in chroot environment
check_chroot() {
    if ischroot; then
        log_info "Not executing in chroot environment."
        exit 0
    fi
}

# Check if running in nspawn or Docker
check_container_env() {
    local init_process
    init_process=$(cat /proc/1/comm 2>/dev/null) || return 1

    if [ "$init_process" != "systemd" ]; then
        log_info "Not executing in systemd-based container (nspawn/Docker)."
        exit 0
    fi
}

# Load locale configuration
load_locale_config() {
    if [ -f /etc/default/locale ]; then
        . /etc/default/locale
    else
        log_warn "Locale config not found: /etc/default/locale"
    fi
}

# Extract language codes from $LANG
get_locale_arr() {
    [ -z "$LANG" ] && return

    # Full lang code e.g. zh_CN.UTF-8
    echo "$LANG"

    # Remove encoding part e.g. zh_CN
    local lang=${LANG%.*}
    echo "$lang"

    # Remove region part e.g. zh
    lang=${lang%_*}
    echo "$lang"
}

# Find localized file by pattern and available locales
find_localized_file() {
    local pattern="$1"
    local lang
    for lang in $(get_locale_arr); do
        local f="${pattern//@lang/$lang}"
        if [ -f "$f" ]; then
            echo "$f"
            return 0
        fi
    done
    echo ""
    return 0
}

# Get the device mounted at a given path
get_mount_point_dev() {
    findmnt --target "$1" -n -f -v | awk '{print $2}'
}

# Try to resolve real device name for LVM/dm devices
get_real_device_name() {
    local dev_name="$1"
    local dm_output_list=$(dmsetup deps -o devname)
    local retry_idx=1
    local parent_dev
    local real_dev=

    while [ $retry_idx -le 5 ]; do
        parent_dev=$(echo "$dm_output_list" | grep -w "^${dev_name}:" | sed -n 's/.*(\(.*\)).*/\1/p' )

        if [ ! -b "/dev/mapper/$parent_dev" ]; then
            if [ -b "/dev/$parent_dev" ]; then
                real_dev="$parent_dev"
            fi
            break
        else
            dev_name="$parent_dev"
            ((retry_idx++))
        fi
    done

    if [ -z "$real_dev" ]; then
        log_error "Could not resolve real device for $1"
        real_dev="$1"
    fi

    echo "$real_dev"
}

# Generate config file with root device info
generate_config_file() {
    local fix_init_root_dev=$(get_mount_point_dev /) || {
        log_warn "Failed to get mount point of /"
        return 1
    }

    local root_lvol=""  # To store logical volume path if exists

    if [[ "$fix_init_root_dev" == /dev/mapper/* && -x /sbin/dmsetup ]]; then
        local base_dev=$(basename "$fix_init_root_dev")
        root_lvol="$fix_init_root_dev"  # Save logical volume path
        local real_dev=$(get_real_device_name "$base_dev")

        if [ -n "$real_dev" ]; then
            echo "The root dev is: $root_lvol, real root device is: /dev/$real_dev"
            fix_init_root_dev="/dev/$real_dev"  # Now fix_init_root_dev becomes the real device
        fi
    fi

    local fix_init_root_fstype=$(blkid -o value -s TYPE "$fix_init_root_dev" 2>/dev/null) || {
        log_warn "Failed to get filesystem type of $fix_init_root_dev"
        echo "Failed to get filesystem type of $fix_init_root_dev" >> "$tmp_fix_file"
    }

    # Always write real device to ROOT_DEV and ROOT_TYPE
    echo "ROOT_DEV=$fix_init_root_dev" > "$tmp_config_file"
    echo "ROOT_TYPE=$fix_init_root_fstype" >> "$tmp_config_file"
    echo "root dev: $fix_init_root_dev type: $fix_init_root_fstype"
    if [ -n "$root_lvol" ]; then
        local root_lvol_type=$(blkid -o value -s TYPE "$root_lvol" 2>/dev/null) || {
            log_warn "Failed to get filesystem type of $root_lvol"
            echo "Failed to get filesystem type of $root_lvol" >> "$tmp_fix_file"
        }
        echo "ROOT_LVOL=$root_lvol" >> "$tmp_config_file"
        echo "ROOT_LVOL_TYPE=$root_lvol_type" >> "$tmp_config_file"
        echo "logical volume: $root_lvol type: $root_lvol_type"
    fi

    copy_file_wrapper "$tmp_config_file" /etc/deepin-fix-init.cfg
}

# Main function to orchestrate all operations
main() {
    # Step 1: Copy binaries and resources
    copy_exec_wrapper /usr/bin/deepin-fix-init /bin/
    copy_file_wrapper /usr/lib/terminfo/l/linux
    # becasue kernel support chinese font, so we don't need to copy fbterm
    #copy_file_wrapper /usr/share/terminfo/f/fbterm
    #copy_exec_wrapper /bin/fbterm /bin/
    copy_exec_wrapper /bin/gettext /bin/
    copy_file_wrapper /usr/share/fonts/truetype/unifont/unifont.ttf
    copy_file_wrapper /usr/share/locale/fix-init-locale-archive /usr/lib/locale/locale-archive
    copy_file_wrapper /etc/default/locale
    copy_file_wrapper /bin/gettext.sh

    # Step 2: Environment checks
    check_chroot
    check_container_env

    # Step 3: Locale handling
    load_locale_config

    local dialog_mo
    dialog_mo=$(find_localized_file "/usr/share/locale/@lang/LC_MESSAGES/dialog.mo")
    if [ -n "$dialog_mo" ]; then
        copy_file_wrapper "$dialog_mo"
    else
        log_warn "No dialog.mo found for current locale"
    fi

    local fix_init_mo
    fix_init_mo=$(find_localized_file "/usr/share/locale/@lang/LC_MESSAGES/deepin-fix-init.mo")
    if [ -n "$fix_init_mo" ]; then
        copy_file_wrapper "$fix_init_mo"
    else
        log_warn "No deepin-fix-init.mo found for current locale"
    fi

    # Step 4: Configuration generation
    generate_config_file || {
        log_warn "cann't generate config file"
        echo "cann't generate config file" >> "$tmp_fix_file"
    }

    # Step 5: Handle failure logs
    if [ -s "$tmp_fix_file" ]; then
        copy_file_wrapper "$tmp_fix_file" /etc/deepin-fix-install-init.log
    fi

    # Step 6: Clean up
    rm -f "$tmp_config_file"
    rm -f "$tmp_fix_file"
}

# =============
# Run main
# =============
main "$@"