#!/usr/bin/env bash
# shellcheck source=/dev/null
set -Eeuo pipefail

SELF_PATH="$(readlink -f "${BASH_SOURCE[0]}")"
BASE_DIR="${SELF_PATH%/*}"
SCRIPT_DIR="${BASE_DIR}/scripts"

if [[ "${ARTIX_RUNTIME_DIR:-}" != "/tmp/artix-run" && -d /tmp ]]; then
    mkdir -p /tmp/artix-run
    cp -a "${BASE_DIR}" /tmp/artix-run/
    export ARTIX_RUNTIME_DIR=/tmp/artix-run
    exec "/tmp/artix-run/${BASE_DIR##*/}/install" "$@"
    exit 0
fi

_die_early() {
    printf '\n\e[1;31m[!] %s\e[0m\n' "${1:-unknown error}" >&2
    exit 1
}

installer_abort() {
    clear
    printf '\n[!] Installation interrupted.\n' >&2
    printf '[!] The installation was NOT completed.\n' >&2
    exit 130
}

installer_error() {
    local rc="${1:-1}" line="${2:-unknown}"
    clear
    printf '\n[!] Installation failed at line: %s\n' "${line}" >&2
    printf '[!] Exit status: %s\n' "${rc}" >&2
    if [[ -f /tmp/artix-installer/install.log ]]; then
        printf '\n[!] Last 10 lines of install log:\n' >&2
        tail -10 /tmp/artix-installer/install.log >&2
    fi
    if [[ -f /tmp/artix-migration-debug.log ]]; then
        printf '\n[!] Migration debug log available at: /tmp/artix-migration-debug.log\n' >&2
        printf '[!] Last 20 lines:\n' >&2
        tail -20 /tmp/artix-migration-debug.log >&2
    fi
    printf '\n[!] The installation was NOT completed.\n' >&2
    exit "${rc}"
}

self_update_installer() {
    local -a restart_args=("$@")
    local repo_url='https://github.com/realvolk/ArtixForge.git' tmp_dir
    tmp_dir="$(mktemp -d)"
    printf '[*] Downloading latest installer...\n'
    if ! git clone --depth 1 "${repo_url}" "${tmp_dir}" >/dev/null 2>&1; then
        printf '[!] Failed to download latest installer.\n'
        rm -rf "${tmp_dir}"
        return 1
    fi
    if [[ ! -f "${tmp_dir}/install" ]]; then
        printf '[!] Invalid installer payload received.\n'
        rm -rf "${tmp_dir}"
        return 1
    fi
    printf '[*] Replacing old installer files...\n'
    find "${BASE_DIR}" -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} +
    cp -a "${tmp_dir}/." "${BASE_DIR}/"
    chmod +x "${BASE_DIR}/install"
    rm -rf "${tmp_dir}"
    printf '[*] Updated %s -> %s\n' "${local_version}" "${remote_version}"
    printf '[*] Restarting updated installer...\n'
    sleep 1
    exec "${BASE_DIR}/install" "${restart_args[@]}"
}

check_installer_version() {
    local local_version remote_version
    [[ -f "${BASE_DIR}/VERSION" ]] || return 0
    local_version="$(tr -d '[:space:]' < "${BASE_DIR}/VERSION")"
    remote_version="$(curl -fsSL 'https://raw.githubusercontent.com/realvolk/ArtixForge/main/VERSION' 2>/dev/null | tr -d '[:space:]' || true)"
    [[ -n "${remote_version}" ]] || return 0
    if [[ "${local_version}" == "${remote_version}" ]]; then return 0; fi
    if [[ "$(printf '%s\n%s\n' "${local_version}" "${remote_version}" | sort -V | tail -n1)" != "${remote_version}" ]]; then return 0; fi
    if tui_yesno "Installer Outdated" "Installed: ${local_version}\nLatest: ${remote_version}\n\nUpdate now?"; then
        if self_update_installer "$@"; then exit 0; fi
        if ! tui_yesno "Update Failed" "Continue anyway?"; then clear; printf '[*] Installation cancelled.\n'; exit 0; fi
    else
        if ! tui_yesno "Continue Anyway" "This installer may contain bugs already fixed upstream.\nContinue using the outdated version?"; then clear; printf '[*] Installation cancelled.\n'; exit 0; fi
    fi
}

verify_installer_layout() {
    local required_files=( common.sh state.sh kernels.sh )
    local required_dirs=( tui storage install post stages recovery )
    for file in "${required_files[@]}"; do [[ -f "${SCRIPT_DIR}/${file}" ]] || return 1; done
    for dir in "${required_dirs[@]}"; do [[ -d "${SCRIPT_DIR}/${dir}" ]] || return 1; done
    [[ -d "${SCRIPT_DIR}/tui/menus" ]] || return 1
    [[ -d "${POWERUSER_DIR:-${BASE_DIR}/poweruser}/tui/menup" ]] || return 1
    [[ -d "${BASE_DIR}/iso" ]] || return 1
    [[ -d "${BASE_DIR}/migrations" ]] || return 1
    return 0
}

source_tree() {
    local dir file
    for dir in "$@"; do
        [[ -d "${SCRIPT_DIR}/${dir}" ]] || { printf '[!] missing directory: %s\n' "${dir}" >&2; return 1; }
        while IFS= read -r -d '' file; do
            printf '[*] Sourcing: %s\n' "${file}" >&2
            source "${file}" || { printf '[!] Failed to source: %s\n' "${file}" >&2; return 1; }
        done < <(find "${SCRIPT_DIR}/${dir}" -maxdepth 1 -type f -name '*.sh' -print0 | sort -z)
    done
}

trap 'installer_abort' INT TERM
trap 'installer_error $? ${LINENO}' ERR

if ! verify_installer_layout; then
    printf '[*] Installer layout is incomplete.\n'
    printf '[*] Attempting automatic repair...\n'
    if ! self_update_installer; then
        _die_early 'failed to repair installer layout'
    fi
    exit 0
fi

source "${SCRIPT_DIR}/common.sh"
source "${SCRIPT_DIR}/state.sh"
source "${SCRIPT_DIR}/kernels.sh"
source "${BASE_DIR}/iso/tui.sh" 2>/dev/null || true
source_tree tui storage install post stages recovery

MODE=""
DEBUG="false"
ARTIX_BOOT_MODE=""

detect_boot_mode() {
    if [[ -d /sys/firmware/efi ]]; then
        ARTIX_BOOT_MODE="uefi"
        log_info "UEFI boot detected"
    else
        ARTIX_BOOT_MODE="bios"
        log_info "BIOS/Legacy boot detected – UEFI features disabled"
    fi
    export ARTIX_BOOT_MODE
    state_set ARTIX_BOOT_MODE "${ARTIX_BOOT_MODE}"
}

main_menu() {
    while true; do
        local -a menu_items=(
            "Automatic – guided installation"
            "Manual – detect existing partitions"
        )

        if [[ -f /tmp/artix-installer/migration-stage.conf ]]; then
            menu_items+=("Resume Migration – continue interrupted migration")
        fi
        if [[ -f /tmp/artix-installer/iso-build-stage.conf ]]; then
            menu_items+=("Resume ISO Build – continue interrupted ISO build")
        fi
        if [[ -f "${STATE_FILE}" ]] && grep -q '^DISK=' "${STATE_FILE}" 2>/dev/null; then
            menu_items+=("Resume Installation – continue interrupted install")
        fi

        menu_items+=("Advanced – recovery, power user, migration, ISO")

        local mode
        mode=$(tui_menu "ArtixForge v9" "Select installation mode:" "${menu_items[@]}") || exit 1

        case "${mode}" in
            Automatic*)     MODE='auto' ; break ;;
            Manual*)        MODE='manual' ; break ;;
            Advanced*)
                local advanced_choice
                advanced_choice=$(tui_menu "Advanced" "Select advanced mode:" \
                    "Recovery – scan /mnt for existing system" \
                    "Power User – source‑built packages" \
                    "System Migration – convert init or desktop" \
                    "Build ISO – create a custom live ISO" \
                    "Back") || continue
                case "${advanced_choice}" in
                    Recovery*)          MODE='recovery' ; break ;;
                    Power*)             MODE='power' ; break ;;
                    "System Migration"*) MODE='migrate' ; break ;;
                    "Build ISO"*)       MODE='iso' ; break ;;
                    *)                  continue ;;
                esac
                ;;
            *Migration*)    MODE='migrate' ; break ;;
            *ISO*)          MODE='iso' ; break ;;
            *Installation*) MODE='resume' ; break ;;
            *)              MODE='auto' ; break ;;
        esac
    done

    if tui_yesno "Debug Mode" "Enable debug mode (verbose logging)?"; then
        DEBUG='true'
    else
        DEBUG='false'
    fi
    tui_msg_quick "Mode Selected" "Mode: ${MODE}   Debug: ${DEBUG}"
}

run_install_pipeline() {
    stage_preflight || die 'preflight stage failed'
    stage_storage   || die 'storage stage failed'
    stage_base      || die 'base stage failed'
    if [[ "$(state_get POWER_USER no)" == "yes" ]]; then
        stage_poweruser || die 'power user build stage failed'
    fi
    stage_chroot    || die 'chroot stage failed'
    stage_init      || die 'init configuration stage failed'
    stage_post      || die 'post-install stage failed'
    stage_finalize  || die 'finalization stage failed'
}

start_auto_install() {
    rm -f /tmp/artix-installer/state.conf
    tui_collect_install_config
    tui_show_summary
    if ! tui_yesno "Begin Installation" "Proceed with installation?"; then
        clear; printf '[*] Installation cancelled.\n'; exit 0
    fi
    state_save
    rm -f /tmp/artix-installer/stages/*.done 2>/dev/null || true
    run_install_pipeline
}

start_manual_install() {
    rm -f /tmp/artix-installer/state.conf
    state_set INSTALL_MODE manual
    run_install_pipeline
}

resume_install() {
    if [[ -f /tmp/artix-installer/migration-stage.conf ]]; then
        log_info "Resuming migration..."
        return 0
    fi
    if [[ -f /tmp/artix-installer/iso-build-stage.conf ]]; then
        log_info "Resuming ISO build..."
        return 0
    fi
    if [[ ! -f "${STATE_FILE}" ]]; then die 'no saved installer state found'; fi
    state_load
    [[ -n "${DISK:-}" ]] || die 'saved installer state is incomplete'
    run_install_pipeline
}

start_recovery_install() {
    local recovery_status
    if ! recovery_detect_install; then
        tui_msg "Recovery Mode" "No installation found at /mnt."
        if tui_yesno "Auto-mount" "Attempt to automatically unlock LUKS, activate LVM, and mount the installation?"; then
            recovery_mount_all
        else
            clear; tui_msg_quick "Recovery Cancelled" "Recovery cancelled by user."; exit 0
        fi
    fi

    recovery_import_state
    recovery_status="$(recovery_get_status)"

    if ! tui_yesno "Recovery Mode" \
"Detected an existing installation mounted at /mnt.

${recovery_status}

This usually means a previous installation
was interrupted or partially completed.

Attempt recovery and continue installation?"; then
        clear; tui_msg_quick "Recovery Cancelled" "Recovery cancelled by user."; exit 0
    fi
    log_info "Entering recovery mode..."

    while true; do
        local recovery_choice
        recovery_choice=$(tui_menu "Recovery Options" "What would you like to do?" \
            "View system status" \
            "Repair detected issues" \
            "Fix everything (kernel, initramfs, GRUB, fstab)" \
            "Repair filesystem corruption (safe or destructive)" \
            "Scan for rootkits" \
            "Untrusted Recovery (rootkit hunt + malware scan)" \
            "Full reinstall (run installer)" \
            "Return to main menu" \
            "Exit") || exit 1

        case "${recovery_choice}" in
            "View system status")
                tui_msg "System Status" "$(recovery_get_status)"
                ;;
            "Repair detected issues")
                repair_detected_issues
                tui_msg "Repair Complete" "Detected issues have been repaired.\n\nRun 'View system status' to verify."
                ;;
            "Fix everything"*)
                repair_system
                tui_msg "Repair Complete" "Full system repair completed.\n\nRun 'View system status' to verify."
                ;;
            "Repair filesystem"*)
                repair_filesystem
                ;;
            "Scan for rootkits")
                detect_rootkits
                tui_msg "Scan Complete" "Rootkit scan finished. Check /tmp/rkhunter.log"
                ;;
            "Untrusted Recovery"*)
                untrusted_recovery
                ;;
            "Full reinstall"*)
                if tui_yesno "Full Reinstall" "This will wipe recovery state and start a fresh installation. Continue?"; then
                    rm -f /tmp/artix-installer/state.conf
                    rm -f /tmp/artix-installer/stages/*.done 2>/dev/null || true
                    umount -R /mnt 2>/dev/null || true
                    MODE='auto'
                    start_auto_install
                    return
                fi
                ;;
            "Return to main menu")
                clear
                main_menu
                return
                ;;
            "Exit")
                clear
                tui_msg_quick "Recovery" "Recovery mode exited. System remains at /mnt."
                exit 0
                ;;
        esac
    done
}

start_system_migration() {
    if [[ -f "${BASE_DIR}/migrations/migrate.sh" ]]; then
        source "${BASE_DIR}/migrations/migrate.sh"
        tui_migration_menu
    else
        tui_msg_quick "Not Available" "Migration module not found at migrations/migrate.sh"
    fi
}

main() {
    ensure_dirs
    require_root
    detect_boot_mode

    if ! command -v gum &>/dev/null; then
        if [[ -f "${BASE_DIR}/bin/gum" ]]; then
            install -Dm755 "${BASE_DIR}/bin/gum" /usr/local/bin/gum
        else
            printf '[*] Gum not found. Installing...\n'
            pacman -Sy --noconfirm gum 2>/dev/null || {
                printf '[!] Failed to install gum. Install it manually and retry.\n' >&2
                exit 1
            }
        fi
    fi

    if [[ "${1:-}" == "--non-interactive" ]]; then
        source "${SCRIPT_DIR}/noninteractive.sh"
        state_load
        MODE="$(state_get MODE auto)"
        log_info "Non‑interactive mode: ${MODE}"
        case "${MODE}" in
            auto|manual)
                state_set INSTALL_MODE "${MODE}"
                stage_preflight || die 'preflight stage failed'
                stage_storage   || die 'storage stage failed'
                stage_base      || die 'base stage failed'
                [[ "$(state_get POWER_USER no)" == "yes" ]] && stage_poweruser || true
                stage_chroot    || die 'chroot stage failed'
                stage_init      || die 'init configuration stage failed'
                stage_post      || die 'post-install stage failed'
                stage_finalize  || die 'finalization stage failed'
                ;;
            resume)
                if [[ -f /tmp/artix-installer/migration-stage.conf ]]; then
                    local mig_type mig_src mig_tgt
                    state_load
                    mig_type="$(state_get MIGRATION_TYPE '')"
                    mig_src="$(state_get MIGRATION_SRC '')"
                    mig_tgt="$(state_get MIGRATION_TGT '')"
                    if [[ -n "${mig_type}" && -n "${mig_src}" && -n "${mig_tgt}" ]]; then
                        log_info "Resuming migration: ${mig_type} ${mig_src} → ${mig_tgt}"
                        if [[ "${mig_type}" == "init" ]]; then
                            source "${BASE_DIR}/migrations/inits/common.sh"
                            run_init_migration "${mig_src}" "${mig_tgt}"
                        else
                            source "${BASE_DIR}/migrations/des/common.sh"
                            run_de_migration "${mig_src}" "${mig_tgt}"
                        fi
                    fi
                elif [[ -f /tmp/artix-installer/iso-build-stage.conf ]]; then
                    local profile_name init kernel offline boot_mode
                    state_load
                    profile_name="$(state_get QUICK_PROFILE 'Desktop')"
                    init="$(state_get INIT 'openrc')"
                    kernel="$(state_get KERNEL_CHOICE 'linux')"
                    offline="$(state_get ALLOW_OFFLINE 'no')"
                    boot_mode="$(state_get ISO_BOOT_MODE 'live')"
                    log_info "Resuming ISO build: ${profile_name}"
                    source "${BASE_DIR}/iso/build.sh"
                    build_artix_iso "${profile_name}" "${init}" "${kernel}" "${offline}" "${boot_mode}"
                else
                    resume_install
                fi
                ;;
            recovery)
                local action
                action="$(state_get RECOVERY_ACTION 'View system status')"
                log_info "Recovery action: ${action}"
                if ! recovery_detect_install; then
                    recovery_mount_all || die "Failed to mount target"
                fi
                recovery_import_state
                case "${action}" in
                    "Repair detected issues") repair_detected_issues ;;
                    "Fix everything"*)       repair_system ;;
                    "Repair filesystem"*)    repair_filesystem ;;
                    "Scan for rootkits")     detect_rootkits ;;
                    "Untrusted Recovery"*)   untrusted_recovery ;;
                    "Full reinstall"*)
                        rm -f /tmp/artix-installer/state.conf
                        rm -f /tmp/artix-installer/stages/*.done 2>/dev/null || true
                        umount -R /mnt 2>/dev/null || true
                        MODE='auto'
                        start_auto_install
                        return
                        ;;
                    *)
                        tui_msg "System Status" "$(recovery_get_status)"
                        ;;
                esac
                log_info "Recovery action completed."
                ;;
            power)
                state_set POWER_USER "yes"
                stage_preflight || die 'preflight stage failed'
                stage_storage   || die 'storage stage failed'
                stage_base      || die 'base stage failed'
                stage_poweruser || die 'power user stage failed'
                stage_chroot    || die 'chroot stage failed'
                stage_init      || die 'init configuration stage failed'
                stage_post      || die 'post-install stage failed'
                stage_finalize  || die 'finalization stage failed'
                ;;
            iso)
                if ! command -v buildiso &>/dev/null; then
                    log_info "Installing artools and iso-profiles..."
                    pacman -S --noconfirm artools iso-profiles || die "Failed to install artools"
                    modprobe loop
                fi
                source "${BASE_DIR}/iso/tui.sh"
                local profile_name init kernel offline boot_mode
                profile_name="$(state_get QUICK_PROFILE 'Desktop')"
                init="$(state_get INIT 'openrc')"
                kernel="$(state_get KERNEL_CHOICE 'linux')"
                offline="$(state_get ALLOW_OFFLINE 'no')"
                boot_mode="$(state_get ISO_BOOT_MODE 'live')"
                source "${BASE_DIR}/iso/build.sh"
                build_artix_iso "${profile_name}" "${init}" "${kernel}" "${offline}" "${boot_mode}"
                ;;
            migrate)
                local mig_type mig_src mig_tgt
                mig_type="$(state_get MIGRATION_TYPE '')"
                mig_src="$(state_get MIGRATION_SRC '')"
                mig_tgt="$(state_get MIGRATION_TGT '')"
                if [[ -z "${mig_type}" || -z "${mig_src}" || -z "${mig_tgt}" ]]; then
                    die "Migration state incomplete – run GUI configuration first"
                fi
                if [[ "${mig_type}" == "init" ]]; then
                    source "${BASE_DIR}/migrations/inits/common.sh"
                    run_init_migration "${mig_src}" "${mig_tgt}"
                else
                    source "${BASE_DIR}/migrations/des/common.sh"
                    run_de_migration "${mig_src}" "${mig_tgt}"
                fi
                ;;
            *)
                log_error "Unknown mode: ${MODE}"
                exit 1
                ;;
        esac
        log_info "Installation complete. You may now reboot."
        exit 0
    fi

    if [[ -n "${DISPLAY:-}" || -n "${WAYLAND_DISPLAY:-}" ]]; then
        if [[ -d "${BASE_DIR}/forge-gui" ]]; then
            if tui_yesno "GUI Installer" "Graphical environment detected.\n\nUse GUI installer (GTK4) instead of TUI?"; then
                clear
                log_info "Launching GUI configuration window..."
                export GUM_TITLE_COLOR="${GUM_TITLE_COLOR:-212}"
                export GUM_ACCENT_COLOR="${GUM_ACCENT_COLOR:-34}"
                export DISPLAY="${DISPLAY:-:0}"
                export XAUTHORITY="${XAUTHORITY:-${HOME}/.Xauthority}"
                command -v xhost &>/dev/null && xhost +SI:localuser:root 2>/dev/null || true

                local venv_dir="/tmp/artix-gui-venv"
                if [[ ! -d "${venv_dir}" ]]; then
                    log_info "Setting up Python virtual environment for GUI..."
                    pacman -S --noconfirm --needed python-virtualenv gtk4 libadwaita python-gobject python-jsonschema
                    python3 -m venv "${venv_dir}" --system-site-packages
                    "${venv_dir}/bin/pip" install jsonschema 2>/dev/null || true
                fi
                unset GTK_MODULES GTK_PATH GTK_THEME GTK_EXE_PREFIX GTK_DATA_PREFIX GTK_IM_MODULE GTK_IM_MODULE_FILE
                cd "${BASE_DIR}/forge-gui" && PYTHONPATH=".:${PYTHONPATH:-}" "${venv_dir}/bin/python3" -m forge_ui.cli --mode config > /tmp/gui-output.log 2>&1 || true

                if [[ -f "${STATE_FILE}" ]] && grep -q '^DISK=' "${STATE_FILE}" 2>/dev/null; then
                    log_info "GUI configuration complete. Starting installation..."
                    MODE="$(grep '^MODE=' "${STATE_FILE}" 2>/dev/null | head -1 | cut -d= -f2 | tr -d '"')"
                    MODE="${MODE:-auto}"
                    log_info "Mode: ${MODE}"
                    exec "$0" --non-interactive
                    exit 0
                else
                    log_error "GUI configuration was not completed. Falling back to TUI."
                fi
            fi
        elif command -v forge-gui &>/dev/null; then
            if tui_yesno "GUI Installer" "Graphical environment detected.\n\nUse GUI installer (GTK4) instead of TUI?"; then
                clear
                log_info "Launching GUI configuration window from PATH..."
                export GUM_TITLE_COLOR="${GUM_TITLE_COLOR:-212}"
                export GUM_ACCENT_COLOR="${GUM_ACCENT_COLOR:-34}"
                forge-gui --mode config
                if [[ -f "${STATE_FILE}" ]] && grep -q '^DISK=' "${STATE_FILE}" 2>/dev/null; then
                    log_info "GUI configuration complete. Starting installation..."
                    MODE="$(grep '^MODE=' "${STATE_FILE}" 2>/dev/null | head -1 | cut -d= -f2 | tr -d '"')"
                    MODE="${MODE:-auto}"
                    log_info "Mode: ${MODE}"
                    exec "$0" --non-interactive
                    exit 0
                else
                    log_error "GUI configuration was not completed. Falling back to TUI."
                fi
            fi
        fi
    fi

    clear
    main_menu

    if [[ "${DEBUG}" == 'true' ]]; then
        export ARTIX_DEBUG='true'
        exec 19> "${BASE_DIR}/artix-debug.log"
        export BASH_XTRACEFD=19
        export PS4='+ ${BASH_SOURCE}:${LINENO}:${FUNCNAME[0]}: '
        set -x
    fi

    check_installer_version

    case "${MODE}" in
        auto)     start_auto_install ;;
        manual)   start_manual_install ;;
        resume)   resume_install ;;
        recovery) start_recovery_install ;;
        power)    MODE='power' ; state_set POWER_USER "yes" ; start_auto_install ;;
        migrate)  start_system_migration ;;
        iso)      start_iso_build ;;
        *)        printf '\e[1;31mNo mode selected. Exiting.\e[0m\n'; exit 1 ;;
    esac
}

main "$@"