/**
 * ./src/appimage/dependency-manager.ts
 * penguins-eggs v.25.11.x / ecmascript 2020
 * author: Piero Proietti
 * email: piero.proietti@gmail.com
 * license: MIT
 */
import * as fs from 'fs';
import * as path from 'path';
import Distro from '../classes/distro.js';
import Diversions from '../classes/diversions.js';
import { execSync } from '../lib/utils.js';
const ALPINE_PACKAGES = [
    'alp-conf',
    'apk-tools',
    'bash',
    'cryptsetup',
    'curl',
    'dosfstools',
    'e2fsprogs',
    'efibootmgr',
    'findutils',
    'git',
    'grub',
    'grub-efi',
    'isolinux',
    'jq',
    'linux-firmware',
    'lvm2',
    'mtools',
    'ncurses',
    'nodejs',
    'openssl',
    'parted',
    'procps',
    'py3-setuptools',
    'rsync',
    'sfdisk',
    'shadow',
    'squashfs-tools',
    'syslinux',
    'tar',
    'xorriso',
    'xz',
    'zstd'
].join(' ');
const META_PACKAGE_NAME = 'penguins-eggs-deps';
const ALPINE_VIRTUAL_PKG = '.penguins-eggs-deps'; // Nota il punto iniziale
export class DependencyManager {
    familyId;
    appRoot;
    distro;
    constructor() {
        this.distro = new Distro();
        this.familyId = this.distro.familyId;
        // Gestione specifica per Manjaro (che si identifica come archlinux ma richiede tools diversi)
        if (this.distro.familyId === 'archlinux' && Diversions.isManjaroBased(this.distro.distroLike)) {
            this.familyId = 'manjaro';
        }
        // Definizione della root per cercare i pacchetti
        if (process.env.APPDIR) {
            // In AppImage, i file sono in $APPDIR/distro (o dove li hai configurati)
            this.appRoot = path.join(process.env.APPDIR, 'distro-packages');
        }
        else {
            // In sviluppo locale, cerchiamo nella cartella corrente o una di fallback
            this.appRoot = process.cwd();
        }
    }
    /**
     * Installa i distro meta-pacchetti corretti in base alla distribuzione.
     */
    installDistroPackages() {
        const depsBase = this.appRoot;
        // CHECK AGGIUNTO: Se è già installato, evitiamo lavoro inutile?
        // Se vuoi forzare l'installazione sempre, rimuovi questo blocco if.
        if (this.isInstalled()) {
            console.log(`[eggs] The meta-packages for ${this.familyId} are already installed.`);
            return true;
        }
        try {
            switch (this.familyId) {
                // ==========================================
                // ALPINE LINUX (Nativo)
                // ==========================================
                case 'alpine': {
                    console.log('[eggs] Alpine dependencies configuration (Virtual Package)...');
                    // --virtual crea un pacchetto fittizio rimuovibile che raggruppa le dipendenze
                    execSync(`apk add --no-cache --virtual ${ALPINE_VIRTUAL_PKG} ${ALPINE_PACKAGES}`, { stdio: 'inherit' });
                    return true;
                }
                // ==========================================
                // ARCHLINUX
                // ==========================================
                case 'archlinux': {
                    const archFile = findPackage(path.join(depsBase, 'arch'), '.zst');
                    if (archFile) {
                        console.log(`[eggs] Installing the Arch Meta-Package: ${path.basename(archFile)}`);
                        execSync(`pacman -Sy --noconfirm && pacman -U --noconfirm "${archFile}"`, { stdio: 'inherit' });
                        return true;
                    }
                    break;
                }
                // ==========================================
                // DEBIAN / UBUNTU FAMILY
                // ==========================================
                case 'debian': {
                    const debFile = findPackage(path.join(depsBase, 'debian'), '.deb');
                    if (debFile) {
                        console.log(`[eggs] Installing Debian Meta-Package: ${path.basename(debFile)}`);
                        // Gestione sicura per l'utente _apt copiando in /tmp
                        const tempDebPath = path.join('/tmp', path.basename(debFile));
                        try {
                            fs.copyFileSync(debFile, tempDebPath);
                            execSync(`apt-get update && apt-get install -y "${tempDebPath}"`, { stdio: 'inherit' });
                        }
                        finally {
                            // Assicuriamoci di pulire il file temporaneo anche in caso di errore
                            if (fs.existsSync(tempDebPath)) {
                                fs.unlinkSync(tempDebPath);
                            }
                        }
                        return true;
                    }
                    break;
                }
                // ==========================================
                // RHEL / CENTOS / ALMA (RPM Family)
                // ==========================================
                case 'el9': {
                    // Cerca file contenente 'el9'
                    const elFile = findPackage(path.join(depsBase, 'rpm'), '.rpm', 'el9');
                    if (elFile) {
                        console.log(`[eggs] Installing EL9 Meta-Package: ${path.basename(elFile)}`);
                        execSync(`dnf install -y "${elFile}"`, { stdio: 'inherit' });
                        return true;
                    }
                    break;
                }
                // ==========================================
                // FEDORA (RPM Family)
                // ==========================================
                case 'fedora': {
                    // Cerca file contenente 'fc42' o 'fc' dentro la cartella rpm
                    const fedoraFile = findPackage(path.join(depsBase, 'rpm'), '.rpm', 'fc42');
                    if (fedoraFile) {
                        console.log(`[eggs] Installing Fedora Meta-Package: ${path.basename(fedoraFile)}`);
                        execSync(`dnf install -y "${fedoraFile}"`, { stdio: 'inherit' });
                        return true;
                    }
                    break;
                }
                // ==========================================
                // MANJARO (Variant: manjaro-tools-iso)
                // ==========================================
                case 'manjaro': {
                    const manjaroFile = findPackage(path.join(depsBase, 'manjaro'), '.zst');
                    if (manjaroFile) {
                        console.log(`[eggs] Installing Manjaro Meta-Package: ${path.basename(manjaroFile)}`);
                        execSync(`pacman -Sy --noconfirm && pacman -U --noconfirm "${manjaroFile}"`, { stdio: 'inherit' });
                        return true;
                    }
                    break;
                }
                // ==========================================
                // OPENSUSE (RPM Family)
                // ==========================================
                case 'opensuse': {
                    const suseFile = findPackage(path.join(depsBase, 'rpm'), '.rpm', 'opensuse');
                    if (suseFile) {
                        console.log(`[eggs] Installing openSUSE Meta-Package: ${path.basename(suseFile)}`);
                        // --allow-unsigned-rpm è necessario perché i nostri pacchetti non sono firmati con GPG
                        execSync(`zypper install -y --allow-unsigned-rpm "${suseFile}"`, { stdio: 'inherit' });
                        return true;
                    }
                    break;
                }
                default: {
                    console.warn(`[eggs] Distribuzione '${this.familyId}' non supportata dai meta-pacchetti automatici.`);
                    return false;
                }
            }
        }
        catch (error) {
            console.error(`[eggs] FATAL ERROR installing dependencies: ${error.message}`);
            // Rilanciamo l'errore per permettere al chiamante di decidere se uscire o continuare
            throw error;
        }
        // Se siamo qui, non è stato trovato il file specifico
        console.warn(`[eggs] No meta-package found for ${this.familyId} in ${depsBase}`);
        return false;
    }
    /**
     * Verifica se i distro-meta-pacchetto sono già installati nel sistema.
     * @returns true se installati, false altrimenti
     */
    isInstalled() {
        try {
            switch (this.familyId) {
                case 'alpine': {
                    // apk info -e esce con 0 se esiste, 1 se no
                    execSync(`apk info -e ${ALPINE_VIRTUAL_PKG}`, { stdio: 'ignore' });
                    return true;
                }
                case 'archlinux':
                case 'manjaro': {
                    // pacman -Q esce con 0 se trovato, 1 se no
                    execSync(`pacman -Q ${META_PACKAGE_NAME}`, { stdio: 'ignore' });
                    return true;
                }
                case 'debian': {
                    // dpkg -s verifica lo stato del pacchetto
                    execSync(`dpkg -s ${META_PACKAGE_NAME}`, { stdio: 'ignore' });
                    return true;
                }
                case 'el9':
                case 'fedora':
                case 'opensuse': {
                    // rpm -q funziona per tutte le distro RPM
                    execSync(`rpm -q ${META_PACKAGE_NAME}`, { stdio: 'ignore' });
                    return true;
                }
                default: {
                    return false;
                }
            }
        }
        catch {
            // Se il comando fallisce (exit code != 0), il pacchetto non è installato
            return false;
        }
    }
    /**
     * Reinstalla i distro-meta-pacchetti: Rimuove e poi Installa.
     * Utile per forzare un aggiornamento delle dipendenze o riparare un'installazione.
     */
    reinstallDistroPackages() {
        console.log(`[eggs] Reinstallazione distro meta-packages per: ${this.familyId}...`);
        // Tentiamo la rimozione (ignoriamo errori se non era installato)
        try {
            this.removeDistroPackages();
        }
        catch {
            console.log(`[eggs] No previous versions found or removal not necessary.`);
        }
        // Procediamo con l'installazione pulita
        return this.installDistroPackages();
    }
    /**
     * Rimuove i distro meta-pacchetti e pulisce le dipendenze.
     */
    removeDistroPackages() {
        console.log(`[eggs] Removing distro meta-packages for: ${this.familyId}...`);
        try {
            switch (this.familyId) {
                // ==========================================
                // ALPINE LINUX
                // ==========================================
                case 'alpine': {
                    console.log('[eggs] Removing Alpine dependencies...');
                    execSync(`apk del ${ALPINE_VIRTUAL_PKG}`, { stdio: 'inherit' });
                    return true;
                }
                // ==========================================
                // ARCHLINUX/MANJARO
                // ==========================================
                case 'archlinux': {
                    console.log(`[eggs] Removing package ${META_PACKAGE_NAME} (Arch/Manjaro)...`);
                    // -Rns: Rimuove pacchetto, configurazioni e dipendenze non usate da altri
                    execSync(`pacman -Rns --noconfirm ${META_PACKAGE_NAME}`, { stdio: 'inherit' });
                    return true;
                }
                // ==========================================
                // DEBIAN / UBUNTU FAMILY
                // ==========================================
                case 'debian': {
                    console.log(`[eggs] Removing package ${META_PACKAGE_NAME} (Debian/Devuan/Ubuntu)...`);
                    // Purge rimuove anche i file di configurazione
                    // autoremove pulisce le dipendenze installate dal meta-pacchetto
                    execSync(`apt-get purge -y ${META_PACKAGE_NAME} && apt-get autoremove -y`, { stdio: 'inherit' });
                    return true;
                }
                // ==========================================
                // RPM FAMILY (EL9 / FEDORA / OPENSUSE)
                // ==========================================
                case 'el9':
                case 'fedora': {
                    console.log(`[eggs] Removing package ${META_PACKAGE_NAME} (RPM/DNF)...`);
                    execSync(`dnf remove -y ${META_PACKAGE_NAME}`, { stdio: 'inherit' });
                    return true;
                }
                case 'opensuse': {
                    console.log(`[eggs] Removing package ${META_PACKAGE_NAME} (Zypper)...`);
                    // -u (--clean-deps) rimuove anche le dipendenze non più necessarie
                    execSync(`zypper rm -y -u ${META_PACKAGE_NAME}`, { stdio: 'inherit' });
                    return true;
                }
                default: {
                    console.warn(`[eggs] Removal not supported automatically for '${this.familyId}'.`);
                    return false;
                }
            }
        }
        catch (error) {
            // Spesso la rimozione fallisce semplicemente perché il pacchetto non c'è.
            // Logghiamo warning invece di errore fatale.
            console.warn(`[eggs] Warning removing: ${error.message}`);
            return false;
        }
    }
}
/**
 * Helper Function (fuori classe, come richiesto)
 * Cerca un file pacchetto in una directory specifica.
 */
function findPackage(dir, ext, pattern = '') {
    try {
        if (!fs.existsSync(dir)) {
            // console.warn(`[DependencyManager] Directory non trovata: ${dir}`);
            return null;
        }
        const files = fs.readdirSync(dir);
        const found = files.find((file) => file.endsWith(ext) && file.includes(pattern));
        return found ? path.join(dir, found) : null;
    }
    catch (error) {
        console.error(`[DependencyManager] Error reading directory ${dir}`, error);
        return null;
    }
}
