#!/bin/bash
#
# SPDX-License-Identifier: Apache-2.0
#
# Authors:
#       2025    Elvis Yao       <ElvisCW.Yao@moxa.com>

# Don't warn quote to prevent word splitting/globbing, or split robustly with mapfile or read in this file
# shellcheck disable=SC2206,SC2207,SC2181,SC2034

#
# global variables
#
export PATH=/sbin:/usr/sbin:/bin:/usr/bin

#
# pre-define variables
#
MENU_TITLE="Moxa x86 SDK Wizard Configuration"
SAVED_CONFIG="${INSTL_TOP_DIR}/.config"
TTY_DEVNAME="/dev/tty"
INDEX_ARR=0
SAVED_ARR=()
dialog_select=(dialog --clear --separate-output --title "Select List" --checklist "Choose one or more options (use space to select):" 20 120 11)

MainMenu() {
        opt=$(dialog --clear --title "${MENU_TITLE}" --no-cancel \
                --menu "Select Options" 20 60 11 1 "Tools" 2 "Drivers" \
                3 "Packages" 4 "Exit" 2>&1 >"${TTY_DEVNAME}")

        for choice in $opt; do
                case $choice in
                1)
                        SelectToolsPage
                        ;;
                2)
                        SelectDriversPage
                        ;;
                3)
                        SelectPackagesPage
                        ;;
                4 | 255)
                        SaveConfigPage
                        clear
                        exit 0
                        ;;
                *)
                        MainMenu
                        return
                        ;;
                esac
        done
}

init_config() {
        load_config "${INSTL_PRODUCT_DIR}/${BOARD_ID}/tools"
        load_config "${INSTL_PRODUCT_DIR}/${BOARD_ID}/drivers"
        load_config "${INSTL_PRODUCT_DIR}/${BOARD_ID}/packages"
}

load_config() {
        local list_file="$1"
        local list_array=()

        list_array+=($(util::parse_product_file "${list_file}" "${LINUX_KERNEL_MAJOR_VER}" "${LINUX_KERNEL_MINOR_VER}" process_file_list))

        for selected_index in "${!list_array[@]}"; do
                selected_index=$((selected_index * 3 + 1))
                if [ $selected_index -lt ${#list_array[@]} ]; then
                        SAVED_ARR+=(${list_array[$selected_index]})
                fi
        done
}

process_file_list() {
        local repo_name="$1"
        local repo_tag="$2"
        local repo_ver
        local option_status="off"

        if util::is_exists "${INSTL_TOP_DIR}"/src/"${repo_name}"-"${repo_tag}"/version; then
                repo_ver="$(cat "${INSTL_TOP_DIR}"/src/"${repo_name}"-"${repo_tag}"/version)"
        else
                repo_ver="unknown"
        fi

        # to show options are selected or not
        for i in "${!SAVED_ARR[@]}"; do
                if [[ "${SAVED_ARR[i]}" == *"$repo_name"* ]]; then
                        option_status="on"
                fi
        done

        echo "${INDEX_ARR} ${repo_name}(${repo_ver}) ${option_status}"
        INDEX_ARR=$((INDEX_ARR + 1))
}

SelectToolsPage() {
        ParseConfig "Tools" "${INSTL_PRODUCT_DIR}/${BOARD_ID}/tools"
}

SelectDriversPage() {
        ParseConfig "Drivers" "${INSTL_PRODUCT_DIR}/${BOARD_ID}/drivers"
}

SelectPackagesPage() {
        ParseConfig "Packages" "${INSTL_PRODUCT_DIR}/${BOARD_ID}/packages"
}

SaveConfigPage() {
        if [ ${#SAVED_ARR[@]} -eq 0 ]; then
                { dialog --title "Save Config" --msgbox "Config is not getting saved. Exit." 8 40 >"${TTY_DEVNAME}"; } 2>&1
                clear
                exit 0
        fi

        # clear .config
        cat /dev/null >"${SAVED_CONFIG}"

        # write back to .confg
        for item in "${SAVED_ARR[@]}"; do
                echo -ne "$item\n" >>"${SAVED_CONFIG}"
        done

        # remove duplicated string
        sort "${SAVED_CONFIG}" | uniq >"${INSTL_TOP_DIR}/.temp"
        mv "${INSTL_TOP_DIR}/.temp" "${SAVED_CONFIG}"

        { dialog --title "Save Config" --msgbox "Config has been saved as '.config'" 8 40 >"${TTY_DEVNAME}"; } 2>&1
}

ParseConfig() {
        local list_type="$1"
        local list_file="$2"
        local list_array=()
        local list_page_items=()
        local list_page_num=()
        local list_selected_num=()

        # reset index
        INDEX_ARR=0
        list_array+=($(util::parse_product_file "${list_file}" "${LINUX_KERNEL_MAJOR_VER}" "${LINUX_KERNEL_MINOR_VER}" process_file_list))

        if [ ${#list_array[@]} -eq 0 ]; then
                { dialog --title "Select $list_type" --msgbox "[$list_type] List is unavailable or empty. Exit." 8 40 >"${TTY_DEVNAME}"; } 2>&1
                MainMenu
        fi

        list_selected_num=($("${dialog_select[@]}" "${list_array[@]}" 2>&1 >"${TTY_DEVNAME}"))
        # if cancelled, go back to last page
        if [ $? -ne 0 ]; then
                MainMenu
        fi

        local num_of_list=0
        for index in "${!list_array[@]}"; do
                index=$((index * 3 + 1))
                if [ $index -lt ${#list_array[@]} ]; then
                        list_page_items+=(${list_array[$index]})
                        list_page_num+=(${num_of_list})
                        num_of_list=$((num_of_list + 1))
                fi
        done

        diff_items=($(get_symmetric_diff list_page_num list_selected_num))
        for index in "${diff_items[@]}"; do
                for item_index in "${!SAVED_ARR[@]}"; do
                        if [[ "${SAVED_ARR[$item_index]}" == "${list_page_items[$index]}" ]]; then
                                unset 'SAVED_ARR[item_index]'
                                SAVED_ARR=("${SAVED_ARR[@]}")
                                break
                        fi
                done
        done
}

get_symmetric_diff() {
        local -n a1=$1
        local -n a2=$2
        local -A seen=()
        local result=()

        # Mark all items in array1
        for item in "${a1[@]}"; do
                seen["$item"]=1
        done

        # Unmark items in array2 if already in seen, else mark them as unique to array2
        for item in "${a2[@]}"; do
                if [[ -n "${seen["$item"]}" ]]; then
                        seen["$item"]=0
                else
                        seen["$item"]=2
                fi
        done

        # Collect items where value is not 0
        for item in "${!seen[@]}"; do
                if [[ ${seen["$item"]} -ne 0 ]]; then
                        result+=("$item")
                fi
        done
        echo "${result[@]}"
}

run_prepare() {
        if command -v apt-get &>/dev/null; then
                if ! command -v dialog &>/dev/null; then
                        apt-get update
                        apt-get install dialog -y
                fi
        elif command -v yum &>/dev/null; then
                if ! command -v dialog &>/dev/null; then
                        yum update -y
                        yum install dialog -y
                fi
        else
                echo "Package manager is not support."
                exit 1
        fi
}

main() {
        source "${INSTL_SCRIPT_DIR}/lib/util.sh"
        source "${INSTL_SCRIPT_DIR}/lib/logger.sh"
        source "${INSTL_SCRIPT_DIR}/lib/version.sh"

        run_prepare
        init_config
        while true; do
                MainMenu
        done
}

main "$@"

exit 0
