import os
import sys
import subprocess
import time
from pathlib import Path
from rich.console import Console
from glob import glob
import shutil
# Import menus do TUI
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from tui import menu_python, menu_iso, menu_libs # pylint: disable=wrong-import-position, import-error

console = Console()

def corrigir_kernel_headers(linux_dir, env):
    """
    Corrige headers incompatíveis com C23 em vários caminhos.
    Adiciona guards para typedef bool / enum { false, true }.
    """
    console.print("[yellow]→ Patching kernel headers for C23 compatibility...[/]")

    header_candidates = [
        "include/linux/stddef.h",
        "include/linux/types.h",
        "include/uapi/linux/stddef.h",
        "include/uapi/linux/types.h",
        "arch/x86/include/asm/stddef.h",
        "arch/x86/include/asm/types.h",
    ]

    # Antes de aplicar os patches:
    safe_run(["make", "prepare"], env=env)
    safe_run(["make", "scripts"], env=env)

    for relpath in header_candidates:
        path = linux_dir / relpath
        if not path.exists():
            continue

        content = path.read_text()
        patched = False

        # Corrige enum false/true
        if "false" in content and "__bool_true_false_are_defined" not in content:
            content = content.replace(
                "enum {\n        false   = 0,\n        true    = 1\n};",
                "#ifndef __bool_true_false_are_defined\n"
                "enum {\n        false   = 0,\n        true    = 1\n};\n"
                "#define __bool_true_false_are_defined 1\n#endif"
            )
            patched = True

        # Corrige typedef _Bool
        if "typedef _Bool" in content and "__STDC_VERSION__" not in content:
            content = content.replace(
                "typedef _Bool                   bool;",
                "#ifndef __cplusplus\n"
                "# if __STDC_VERSION__ < 202000L\n"
                "typedef _Bool bool;\n"
                "# endif\n"
                "#endif"
            )
            patched = True

        if patched:
            path.write_text(content)
            console.print(f"[green]✔ Patched:[/] {relpath}")

    # Corrige Makefile do boot
    boot_makefile = linux_dir / "arch/x86/boot/Makefile"
    if boot_makefile.exists():
        with open(boot_makefile, "a") as f:
            f.write("\n# C23 fix\nccflags-y += -std=gnu11 -Wno-error\n")
        console.print("[cyan]→ Applied local Makefile override for boot code (C23 fix)[/]")

    # Corrige Makefile do boot/compressed
    boot_compr_makefile = linux_dir / "arch/x86/boot/compressed/Makefile"
    if boot_compr_makefile.exists():
        with open(boot_compr_makefile, "a") as f:
            f.write("\n# C23 fix\nccflags-y += -std=gnu11 -Wno-error\n")
        console.print("[cyan]→ Applied local Makefile override for boot/compressed code (C23 fix)[/]")

    # Corrige Makefile do EFI stub
    efi_makefile = linux_dir / "drivers/firmware/efi/libstub/Makefile"
    if efi_makefile.exists():
        with open(efi_makefile, "a") as f:
            f.write("\n# C23 fix\nccflags-y += -std=gnu11 -Wno-error\n")
        console.print("[cyan]→ Applied local Makefile override for EFI stub (C23 fix)[/]")

def corrigir_kernel_overrides(cross_compile):
    env = {
        **os.environ,
        "ARCH": "x86_64",
        "CROSS_COMPILE": cross_compile,
        "LOCALVERSION": "-nfdos",
    }

    console.print("[yellow]→ Aplicando overrides de configuração...[/yellow]")

    # Essenciais do sistema base
    essentials = [
        "CONFIG_PRINTK",
        "CONFIG_TTY",
        "CONFIG_SERIAL_8250",
        "CONFIG_SERIAL_8250_CONSOLE",
        "CONFIG_SERIAL_EARLYCON",
        "CONFIG_DEVTMPFS",
        "CONFIG_DEVTMPFS_MOUNT",
        "CONFIG_BLK_DEV_INITRD",
        "CONFIG_TMPFS",
        "CONFIG_PROC_FS",
        "CONFIG_SYSFS",
        # EXT4 base + alias para ext2
        "CONFIG_PARTITION_ADVANCED",
        "CONFIG_EFI_PARTITION",
        "CONFIG_MSDOS_PARTITION",
        "CONFIG_EXT4_FS",
        "CONFIG_EXT4_USE_FOR_EXT2",
        "CONFIG_CMDLINE_PARTITION",
        "CONFIG_MCORE2",
        #"CONFIG_EXT4_FS_POSIX_ACL",
        #"CONFIG_EXT4_FS_SECURITY",
    ]

    # VirtIO (para bloco, rede, PCI)
    virtio = [
        "CONFIG_PCI",
        "CONFIG_VIRTIO",
        "CONFIG_VIRTIO_MENU",
        "CONFIG_VIRTIO_PCI",
        "CONFIG_VIRTIO_PCI_LEGACY",
        "CONFIG_VIRTIO_BLK",
        "CONFIG_VIRTIO_NET",
        "CONFIG_VIRTIO_CONSOLE",
        "CONFIG_VIRTIO_INPUT",
        "CONFIG_VIRTIO_MMIO",
        "CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES",
        "CONFIG_BLK_MQ_VIRTIO",
        "CONFIG_BLOCK",
        "CONFIG_BLK_DEV",
        "CONFIG_BLOCK_LEGACY_AUTOLOAD",
        "CONFIG_EXPORTFS_BLOCK_OPS",
        "CONFIG_MSDOS_PARTITION",  # assegura parsing de tabela de partições
    ]

    # Debug e early printk
    debug = [
        "CONFIG_DEBUG_KERNEL",
        "CONFIG_EARLY_PRINTK",
        "CONFIG_SERIAL_8250_PNP",
        "CONFIG_DEBUG_INFO_NONE",  # evita symbols extras
    ]

    # Desativa gráficos e Garante compatibilidade máxima de CPU (para manter o kernel leve, limpo e evitar CR4 panics)
    disable_graphics = [
        "CONFIG_VT",
        "CONFIG_VT_CONSOLE",
        "CONFIG_VGA_CONSOLE",
        "CONFIG_FRAMEBUFFER_CONSOLE",
        "CONFIG_DUMMY_CONSOLE",
        "CONFIG_FB",
        "CONFIG_DRM",
        "CONFIG_DRM_I915",
        "CONFIG_LOGO",
        "CONFIG_X86_PAE",
        "CONFIG_X86_5LEVEL",
        "CONFIG_RANDOMIZE_BASE",
        "CONFIG_RETPOLINE",
        "CONFIG_SMAP",
        "CONFIG_SMEP",
        "CONFIG_PAGE_TABLE_ISOLATION",
    ]

    # Habilita todos os conjuntos
    for opt in essentials + virtio + debug:
        safe_run(["scripts/config", "--enable", opt], env=env)

    # garante que o driver não é módulo
    for opt in [
        "CONFIG_VIRTIO_BLK=m",
        "CONFIG_VIRTIO_PCI=m",
        "CONFIG_VIRTIO_PCI_LEGACY=m",
    ]:
        safe_run(["scripts/config", "--disable", opt], env=env)

    # Desativa o que não precisamos
    for opt in disable_graphics:
        safe_run(["scripts/config", "--disable", opt], env=env)

    # Formatos binários básicos
    for opt in [
        "CONFIG_BINFMT_ELF",
        "CONFIG_BINFMT_SCRIPT",
    ]:
        safe_run(["scripts/config", "--enable", opt], env=env)

    # Regera configuração coerente
    safe_run(["make", "olddefconfig"], env=env)

    console.print("[green]✔ Overrides aplicados com sucesso.[/green]")


def safe_run(cmd, **kwargs):
    """Executa um comando e mostra logs legíveis no TUI."""
    console.print(f"[dim]{' '.join(cmd) if isinstance(cmd, list) else cmd}[/dim]")
    subprocess.run(cmd, check=True, **kwargs)

def limpar_rootfs(nfdos_dir):
    rootfs = nfdos_dir / "rootfs"
    initramfs = nfdos_dir / "initramfs.cpio.gz"
    if rootfs.exists():
        console.print("[yellow]🧹 Limpando RootFS anterior...[/yellow]")
        safe_run(f"rm -rf {rootfs}", shell=True)
    if initramfs.exists():
        console.print("[yellow]🧹 Removendo initramfs anterior...[/yellow]")
        safe_run(f"rm -f {initramfs}", shell=True)

def build_e2fsprogs_static(rootfs_dir, e2fsprogs_dir, nfdos_dir, env):
    """
    Compila e instala e2fsprogs (mke2fs/mkfs.ext4/fsck/tune2fs, etc.)
    em modo utilizável dentro do rootfs do NFDOS.

    Não insistimos em binário 100% estático (o toolchain do host pode não ter
    todas as libs *.a), mas garantimos que TODAS as dependências dinâmicas
    (incluindo o loader ld-linux) são copiadas para dentro do initramfs.

    Estratégia:
      - build "in-tree" normal no host
      - copiar binários para <rootfs>/sbin
      - usar `ldd` sobre <rootfs>/sbin/mke2fs e copiar as libs referenciadas
        para dentro do rootfs, mantendo a mesma árvore (/lib64, /lib, /usr/lib, etc)
    """
    import os
    import subprocess
    import shutil
    from pathlib import Path

    rootfs_dir = Path(rootfs_dir)
    e2fsprogs_dir = Path(e2fsprogs_dir)
    nfdos_dir = Path(nfdos_dir)

    # ------------------------------------------------------------------
    # 0. ENV limpo só para e2fsprogs (sem CROSS_COMPILE, KCFLAGS, etc.)
    # ------------------------------------------------------------------
    env_e2 = os.environ.copy()
    for bad in [
        "CROSS_COMPILE",
        "ARCH",
        "KCFLAGS",
        "KBUILD_CFLAGS",
        "KBUILD_AFLAGS",
        "KBUILD_CPPFLAGS",
        "KCFLAGS_FOR_HOST",
    ]:
        env_e2.pop(bad, None)

    # Não vamos forçar -static (queremos algo que compile sempre).
    if "CFLAGS" not in env_e2:
        env_e2["CFLAGS"] = "-O2"

    # ------------------------------------------------------------------
    # 1. Download + unpack se ainda não existir
    # ------------------------------------------------------------------
    if not e2fsprogs_dir.exists() or not any(e2fsprogs_dir.iterdir()):
        print("📦 Obtendo e2fsprogs 1.47.0…")
        tar_path = nfdos_dir / "e2fsprogs-1.47.0.tar.gz"

        if not tar_path.exists():
            subprocess.run([
                "curl", "-L",
                "https://mirrors.edge.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs/v1.47.0/e2fsprogs-1.47.0.tar.gz",
                "-o", str(tar_path),
            ], check=True)

        e2fsprogs_dir.mkdir(parents=True, exist_ok=True)
        subprocess.run([
            "tar", "-xzf", str(tar_path),
            "--strip-components=1",
            "-C", str(e2fsprogs_dir),
        ], check=True)

    # ------------------------------------------------------------------
    # 2. Configurar + compilar (in-tree)
    # ------------------------------------------------------------------
    os.chdir(e2fsprogs_dir)

    subprocess.run(
        ["make", "distclean"],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
    )

    configure_cmd = [
        "./configure",
        "--disable-nls",
        "--disable-fuse2fs",
        "--disable-defrag",
        "--disable-resizer",
        "--enable-libblkid",
        "--enable-libuuid",
        "--enable-static",
        "--disable-shared",
    ]

    print("🧱 Configurando e2fsprogs…")
    subprocess.run(configure_cmd, check=True, env=env_e2)

    print("🔨 Compilando e2fsprogs…")
    subprocess.run(["make", "-j4"], check=True, env=env_e2)

    # ------------------------------------------------------------------
    # 3. Instalar binários no rootfs (substituindo symlinks de BusyBox)
    # ------------------------------------------------------------------
    print("📥 Instalando binários no rootfs…")

    sbin = rootfs_dir / "sbin"
    sbin.mkdir(parents=True, exist_ok=True)

    tools = {
        "misc/mke2fs":   "mke2fs",
        "e2fsck/e2fsck": "e2fsck",
        "misc/tune2fs":  "tune2fs",
        "misc/e2label":  "e2label",
        "misc/dumpe2fs": "dumpe2fs",
    }

    for rel_src, dest_name in tools.items():
        src = e2fsprogs_dir / rel_src
        if not src.exists():
            print(f"  ⚠ {rel_src} não encontrado (pode ser opcional)")
            continue

        dst = sbin / dest_name

        # Se já existir (ficheiro ou symlink), apaga primeiro
        if dst.is_symlink() or dst.exists():
            dst.unlink()

        shutil.copy2(src, dst)
        print(f"  ✔ {dest_name} instalado em {dst}")

    # Symlinks mkfs.ext[234] → mke2fs  e  fsck.ext[234] → e2fsck
    for fs in ("ext2", "ext3", "ext4"):
        link = sbin / f"mkfs.{fs}"
        if link.is_symlink() or link.exists():
            link.unlink()
        link.symlink_to("mke2fs")
        print(f"  🔗 mkfs.{fs} → mke2fs")

    for fs in ("ext2", "ext3", "ext4"):
        link = sbin / f"fsck.{fs}"
        if link.is_symlink() or link.exists():
            link.unlink()
        link.symlink_to("e2fsck")
        print(f"  🔗 fsck.{fs} → e2fsck")

    subprocess.run(["chmod", "-R", "755", str(sbin)], check=True)

    # ------------------------------------------------------------------
    # 4. Copiar dependências dinâmicas para dentro do rootfs
    # ------------------------------------------------------------------
    def inject_dynamic_libs(binary_path: Path, rootfs: Path):
        """
        Usa `ldd` para descobrir libs de que o binário depende e copia-as
        para dentro do rootfs mantendo paths absolutos.
        Exemplo:
          /lib64/ld-linux-x86-64.so.2  -> <rootfs>/lib64/ld-linux-x86-64.so.2
          /lib/x86_64-linux-gnu/libc.so.6 -> <rootfs>/lib/x86_64-linux-gnu/libc.so.6
        """
        print(f"🔎 Resolvendo dependências dinâmicas de {binary_path}…")
        try:
            proc = subprocess.run(
                ["ldd", str(binary_path)],
                text=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                check=True,
            )
        except Exception as e:
            print(f"  ⚠ ldd falhou: {e}")
            return

        for line in proc.stdout.splitlines():
            line = line.strip()
            if not line or "statically linked" in line:
                continue

            # Exemplos de linhas:
            #   linux-vdso.so.1 (0x00007ffc...)
            #   libext2fs.so.2 => /lib/x86_64-linux-gnu/libext2fs.so.2 (0x...)
            #   /lib64/ld-linux-x86-64.so.2 (0x00007f...)
            if "=>" in line:
                left, right = line.split("=>", 1)
                right = right.strip()
                if right == "not found":
                    print(f"  ⚠ dependência não encontrada: {line}")
                    continue
                path = right.split()[0]
            else:
                # linha tipo "/lib64/ld-linux-x86-64.so.2 (0x...)"
                parts = line.split()
                path = parts[0]

            if not path.startswith("/"):
                continue

            src = Path(path)
            if not src.exists():
                print(f"  ⚠ {src} não existe no host (ignorado)")
                continue

            dst = rootfs / src.relative_to("/")
            dst.parent.mkdir(parents=True, exist_ok=True)

            if not dst.exists():
                shutil.copy2(src, dst)
                print(f"  📦 {src} -> {dst}")
            else:
                print(f"  ⏭ {dst} já existe, mantendo")

    # Inject libs para mke2fs (basta este; fsck/tune2fs partilham as libs)
    inject_dynamic_libs(sbin / "mke2fs", rootfs_dir)

    # ------------------------------------------------------------------
    # 5. Voltar ao diretório base do NFDOS
    # ------------------------------------------------------------------
    os.chdir(nfdos_dir)
    print("💚 e2fsprogs instalados no rootfs com sucesso (com libs dinâmicas incluídas)!")

def run():
    while True:
        console.clear()
        console.rule("[bold yellow]Kernel / BusyBox / Python[/bold yellow]")
        console.print("1. Obter código-fonte do Kernel Linux")
        console.print("2. Compilar Kernel com Toolchain NFDOS")
        console.print("3. Obter e compilar BusyBox")
        console.print("4. Compilar Python estatico com Toolchain NFDOS")
        console.print("5. Obter e compilar Bibliotecas do Neurotron")
        console.print("6. Montar RootFS e gerar imagem bootável")
        console.print("7. Gerar imagem ISO e iniciar o NFDOS no QEMU")
        console.print("0. Voltar")

        choice = console.input("\n[cyan]nfdos> [/cyan]")

        base_dir = Path(__file__).resolve().parents[1]
        kernel_dir = base_dir / "_nfdos" / "kernel"
        linux_dir = kernel_dir / "linux"
        nfdos_dir = base_dir / "_nfdos"
        busybox_dir = nfdos_dir / "busybox"
        e2fsprogs_dir = nfdos_dir / "e2fsprogs"
        rootfs_dir = nfdos_dir / "rootfs"
        neurotron_dir = kernel_dir / "neurotron"
        toolchain_prefix = Path.home() / "x-tools" / "x86_64-nfdos-linux-musl"
        cross_compile = f"{toolchain_prefix}/bin/x86_64-nfdos-linux-musl-"

        linux_repo = "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"
        busybox_repo = "git://busybox.net/busybox.git"

        env = {
            **os.environ,		
            "ARCH": "x86_64",
            "CROSS_COMPILE": cross_compile,
            "CFLAGS": "-std=gnu11 -fcommon -Wno-error",
            "LOCALVERSION": "-nfdos",
            "KCFLAGS": "-std=gnu11 -fcommon -Wno-error",
            "HOSTCFLAGS": "-std=gnu11 -fcommon -Wno-error",
            "KBUILD_CFLAGS": "-std=gnu11 -fcommon -Wno-error",
            "KBUILD_AFLAGS": "-std=gnu11 -fcommon",
            "KBUILD_CPPFLAGS": "-std=gnu11 -fcommon",
            "KCFLAGS_FOR_HOST": "-std=gnu11 -Wno-error",
        }

        if choice == "1":
            kernel_dir.mkdir(parents=True, exist_ok=True)
            os.chdir(kernel_dir)
            console.print("[yellow]Baixando código-fonte do Kernel Linux...[/yellow]")
            if not linux_dir.exists():
                safe_run(["git", "clone", "--depth=1", "--branch", "v6.12", linux_repo, "linux"])
            else:
                os.chdir(linux_dir)
                safe_run(["git", "pull"])
            console.print("[green]✔ Kernel atualizado![/green]")

        elif choice == "2":
            os.chdir(linux_dir)
            console.print("[cyan]Compilando Kernel Linux...[/cyan]")

            # Verificação do compilador
            if not Path(cross_compile + "gcc").exists():
                console.print("[red]✗ Toolchain não encontrada![/red]")
                console.print(f"Esperado: {cross_compile}gcc")
                time.sleep(2)
                continue

            # Passo 1 — Limpar tudo antes de começar
            safe_run(["make", "mrproper"], env=env)

            # Passo 2 — Baixar configuração base mínima
            safe_run(["make", "allnoconfig"], env=env)

            # Passo 3 — Aplicar patches C23 aos headers
            corrigir_kernel_headers(linux_dir, env)

            # Passo 4 — Aplicar overrides minimalistas (serial-only, sem VGA)
            corrigir_kernel_overrides(cross_compile)

            # Passo 5 — Regerar dependências e .config
            safe_run(["make", "olddefconfig"], env=env)

            # Passo 6 — Compilar
            safe_run(["make", "-j", str(os.cpu_count())], env=env)

            console.print("[green]✔ Kernel compilado com sucesso![/green]")

        elif choice == "3":
            busybox_dir.mkdir(parents=True, exist_ok=True)
            os.chdir(busybox_dir)
            console.print("[yellow]📦 Baixando e compilando BusyBox...[/yellow]")

            if not (busybox_dir / ".git").exists():
                safe_run(["git", "clone", "--depth=1", busybox_repo, "-b", "master", "."], env=env)

            # 🧹 Limpeza preventiva se houver restos de builds anteriores
            if (busybox_dir / ".config").exists():
                console.print("[cyan]🧼 Limpando build antigo (make mrproper)...[/cyan]")
                safe_run(["make", "mrproper"], env=env)

            console.print("[cyan]🧩 Gerando configuração base (defconfig)...[/cyan]")
            safe_run(["make", "defconfig"], env=env)

            console.print("[cyan]🧠 Aplicando overrides de configuração (persistência + EXT4)...[/cyan]")

            config_updates = {
                # ----------------------------------
                # CORE + STATIC
                # ----------------------------------
                "CONFIG_STATIC": "y",

                # ----------------------------------
                # BLOCK DEVICES / PARTITIONS
                # ----------------------------------
                "CONFIG_BLKID": "y",
                "CONFIG_LSBLK": "y",
                "CONFIG_BLOCKDEV": "y",
                "CONFIG_FDISK": "y",
                "CONFIG_FEATURE_FDISK_WRITABLE": "y",
                "CONFIG_FEATURE_FDISK_ADVANCED": "y",
                "CONFIG_FDISK_SUPPORT_LARGE_DISKS": "y",
                "CONFIG_FEATURE_FDISK_GPT": "y",
                "CONFIG_FEATURE_FDISK_PARTITION_TYPES": "y",
                "CONFIG_SFDISK": "y",
                "CONFIG_MDEV": "y",
                "CONFIG_MDEV_CONF": "y",
                "CONFIG_MDEV_EXEC": "y",
                "CONFIG_HEXDUMP": "y",
                "CONFIG_DD": "y",
                "CONFIG_LOSETUP": "y",
                "CONFIG_WIPEFS": "y",
                "CONFIG_BLKDISCARD": "y",

                # ----------------------------------
                # MOUNT / UMOUNT
                # ----------------------------------
                "CONFIG_MOUNT": "y",
                "CONFIG_UMOUNT": "y",
                "CONFIG_FEATURE_MOUNT_HELPERS": "y",
                "CONFIG_FEATURE_MOUNT_FSTAB": "y",
                "CONFIG_FEATURE_MOUNT_LABEL": "y",

                # volume detection
                "CONFIG_FEATURE_VOLUMEID": "y",
                "CONFIG_FEATURE_VOLUMEID_EXT": "y",
                "CONFIG_FEATURE_VOLUMEID_FAT": "y",
                "CONFIG_FEATURE_VOLUMEID_LINUXSWAP": "y",
                "CONFIG_FEATURE_VOLUMEID_EXFAT": "y",
                "CONFIG_FEATURE_VOLUMEID_NTFS": "y",
                "CONFIG_FEATURE_VOLUMEID_BTRFS": "y",
                "CONFIG_FEATURE_VOLUMEID_ISO9660": "y",

                # ----------------------------------
                # MKFS + EXT4
                # ----------------------------------
                "CONFIG_MKFS": "y",
                "CONFIG_MKFS_EXT2": "y",
                "CONFIG_MKFS_EXT3": "y",
                "CONFIG_MKFS_EXT4": "y",
                "CONFIG_FEATURE_MKFS_EXT2": "y",
                "CONFIG_FEATURE_MKFS_EXT3": "y",
                "CONFIG_FEATURE_MKFS_EXT4": "y",
                "CONFIG_FEATURE_MKFS_EXTENDED": "y",        # ⭐ obrigatório
                "CONFIG_FEATURE_MKFS_FSCK": "y",            # recomendável

                # e2fsprogs (mini)
                "CONFIG_MKE2FS": "y",
                "CONFIG_MKE2FS_EXTENDED": "y",
                "CONFIG_E2LABEL": "y",
                "CONFIG_E2FSCK": "y",
                "CONFIG_TUNE2FS": "y",

                # ----------------------------------
                # FSCK
                # ----------------------------------
                "CONFIG_FSCK": "y",
                "CONFIG_FEATURE_FSCK_EXT2": "y",

                # ----------------------------------
                # UTILITÁRIOS ÚTEIS
                # ----------------------------------
                "CONFIG_LS": "y",
                "CONFIG_LSUSB": "y",
                "CONFIG_STRINGS": "y",
                "CONFIG_STAT": "y",
                "CONFIG_DF": "y",
                "CONFIG_DU": "y",
            }

            for key, value in config_updates.items():
                safe_run([
                    "sed", "-i",
                    f"s/^# {key} is not set/{key}={value}/; t; s/^{key}=.*/{key}={value}/; t; $a\\{key}={value}",
                    ".config"
                ], env=env)

            # 🧠 Shell e utilitários básicos
            safe_run(["sed", "-i", "s/^CONFIG_TC=.*/# CONFIG_TC is not set/", ".config"], env=env)
            safe_run(["sed", "-i", "s/^# CONFIG_ASH is not set/CONFIG_ASH=y/", ".config"], env=env)
            safe_run(["sed", "-i", "s/^# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set/CONFIG_ASH_OPTIMIZE_FOR_SIZE=y/", ".config"], env=env)
            safe_run(["sed", "-i", "s/^# CONFIG_FEATURE_SH_STANDALONE is not set/CONFIG_FEATURE_SH_STANDALONE=y/", ".config"], env=env)

            console.print("[yellow]🔧 Regerando configuração coerente (make oldconfig)...[/yellow]")
            safe_run(["make", "oldconfig"], env=env)

            console.print("[yellow]🔨 Compilando BusyBox (estático, com EXT4 e ferramentas de disco)...[/yellow]")
            safe_run(["make", "-j", str(os.cpu_count())], env=env)

            console.print("[green]✔ BusyBox compilado e instalado com sucesso![/green]")


        elif choice == "4":
            menu_python.run()

        elif choice == "5":
            menu_libs.run()

        elif choice == "6":
            os.chdir(nfdos_dir)
            console.print("[cyan]Montando RootFS e gerando imagem bootável...[/cyan]")

            limpar_rootfs(nfdos_dir)

            rootfs_dir = nfdos_dir / "rootfs"
            rootfs_dir.mkdir(exist_ok=True)

            # Estrutura de diretórios básica
            for d in ["bin", "sbin", "etc", "proc", "sys", "usr/bin", "usr/sbin", "opt/kernel"]:
                (rootfs_dir / d).mkdir(parents=True, exist_ok=True)

            # Garante os device nodes no initramfs
            safe_run(f"mkdir -p {rootfs_dir}/dev", shell=True)
            safe_run(f"sudo mknod -m 600 {rootfs_dir}/dev/console c 5 1", shell=True)
            safe_run(f"sudo mknod -m 666 {rootfs_dir}/dev/null c 1 3", shell=True)
            safe_run(f"sudo mknod -m 600 {rootfs_dir}/dev/ttyS0 c 4 64", shell=True)
            safe_run(f"sudo mknod -m 666 {rootfs_dir}/dev/random c 1 8", shell=True)
            safe_run(f"sudo mknod -m 666 {rootfs_dir}/dev/urandom c 1 9", shell=True)

            # 1. Instalar BusyBox no rootfs
            os.chdir(busybox_dir)
            console.print("[cyan]🔗 Instalando BusyBox no RootFS...[/cyan]")
            safe_run(["make", f"CONFIG_PREFIX={rootfs_dir}", "install"], env=env)
            os.chdir(nfdos_dir)

            build_e2fsprogs_static(rootfs_dir, e2fsprogs_dir, nfdos_dir, env)

            # 2. Garantir permissões corretas
            safe_run(["chmod", "-R", "755", str(rootfs_dir / "bin")])
            safe_run(["chmod", "-R", "755", str(rootfs_dir / "sbin")])

            console.print("[green]✔ BusyBox incluído no rootfs![/green]")

            # Inserir a Lib Python (TODO: No NFDOS V0.2 build “fully frozen”)
            safe_run(f"mkdir -p {rootfs_dir}/usr/lib/python3.13", shell=True)
            safe_run(f"rsync -av --exclude='test' --exclude='idlelib' --exclude='tkinter' \
                {nfdos_dir}/cpython/Lib/ {rootfs_dir}/usr/lib/python3.13/", shell=True)
            
            # --- Copiar binário Python estático para o RootFS ---
            python_bin = nfdos_dir / "python"
            usr_bin = rootfs_dir / "usr" / "bin"
            usr_bin.mkdir(parents=True, exist_ok=True)

            if python_bin.exists():
                console.print("[yellow]→ Adicionando Python estático ao RootFS...[/yellow]")
                safe_run(f"cp {python_bin} {usr_bin}/python3", shell=True)
            else:
                console.print("[red]⚠ Python estático não encontrado em nfdos/python — compilar antes.[/red]")

            # Inserir Neurotron (se existir)
            opt_kernel = rootfs_dir / "opt" / "kernel"
            opt_kernel.mkdir(parents=True, exist_ok=True)

            # ============================================
            # Instalar Neurotron nativamente no RootFS
            # ============================================

            neurotron_src = kernel_dir / "neurotron" / "src"
            neurotron_data = kernel_dir / "neurotron" / "data"
            neurotron_bin = kernel_dir / "neurotron" / "neurotron"   # gerado pelo autotools

            neurotron_root = opt_kernel / "neurotron"
            neurotron_root.mkdir(parents=True, exist_ok=True)

            if neurotron_src.exists():
                console.print("[yellow]→ Instalando código-fonte do Neurotron...[/yellow]")
                safe_run(f"cp -r {neurotron_src} {neurotron_root}/", shell=True)
            else:
                console.print("[red]✗ Código-fonte do Neurotron não encontrado.[/red]")

            if neurotron_data.exists():
                console.print("[yellow]→ Instalando diretório data/ do Neurotron...[/yellow]")
                safe_run(f"cp -r {neurotron_data} {neurotron_root}/", shell=True)

            # Instalar binário /usr/bin/neurotron
            usr_bin = rootfs_dir / "usr" / "bin"
            usr_bin.mkdir(parents=True, exist_ok=True)

            if neurotron_bin.exists():
                console.print("[yellow]→ Instalando wrapper /usr/bin/neurotron[/yellow]")
                safe_run(f"cp {neurotron_bin} {usr_bin}/neurotron", shell=True)
                safe_run(f"chmod +x {usr_bin}/neurotron", shell=True)
            else:
                console.print("[red]✗ Wrapper 'neurotron' não encontrado — corre 'make' em kernel/neurotron[/red]")

            # Instalar terminais
            lterm_dir = rootfs_dir / "usr" / "share" / "terminfo" / "l"
            lterm_dir.mkdir(parents=True, exist_ok=True)
            safe_run(f"cp {nfdos_dir}/linux {lterm_dir}/", shell=True)

            xterm_dir = rootfs_dir / "usr" / "share" / "terminfo" / "x"
            xterm_dir.mkdir(parents=True, exist_ok=True)
            safe_run(f"cp {nfdos_dir}/xterm {xterm_dir}/", shell=True)

            vterm_dir = rootfs_dir / "usr" / "share" / "terminfo" / "v"
            vterm_dir.mkdir(parents=True, exist_ok=True)
            safe_run(f"cp {nfdos_dir}/vt100 {vterm_dir}/", shell=True)

            # Instalar libs externas do Neurotron (se existirem)
            libs_dir = nfdos_dir / "libs"
            site_packages = rootfs_dir / "usr/lib/python3.13/site-packages"
            site_packages.mkdir(parents=True, exist_ok=True)

            lib_files = []
            for ext in ("*.whl", "*.tar.gz", "*.zip", "*.tgz"):
                lib_files.extend(glob(f"{libs_dir}/{ext}"))

            if lib_files:
                libs_str = " ".join(lib_files)
                console.print("[cyan]→ Instalando bibliotecas externas do Neurotron...[/cyan]")
                safe_run(
                    f"pip install --no-deps --target={site_packages} {libs_str}",
                    shell=True
                )
            else:
                console.print("[yellow]⚠️ Nenhuma biblioteca externa encontrada em libs/.[/yellow]")


            # Copiar init real do Neurotron
            safe_run(["cp", str(neurotron_dir / "neurotron.in"), str(rootfs_dir / "init")])
            safe_run(["chmod", "755", str(rootfs_dir / "init")])

            # Script init com chamada ao Neurotron
            init_file = rootfs_dir / "init"
            initramfs_file = nfdos_dir / "initramfs.cpio.gz"

            # Gerar initramfs
            console.print("[blue]Gerando initramfs.cpio.gz...[/blue]")
            if initramfs_file.exists():
                safe_run(f"rm {initramfs_file}", shell=True)
            safe_run(f"cd {rootfs_dir} && find . | cpio -H newc -o | gzip > {initramfs_file}", shell=True)
            console.print("[green]✔ RootFS criado e compactado![/green]")

            # 🧠 Validação do init antes de gerar o initramfs
            console.print("[blue]🔍 Verificando integridade do init...[/blue]")

            # Garante que o init existe
            if not init_file.exists():
                console.print(f"[red]✗ Ficheiro init não encontrado em {init_file}[/red]")
                raise SystemExit(1)

            # Mostra onde ele está dentro do initramfs
            safe_run(f'cd {nfdos_dir} && lsinitramfs initramfs.cpio.gz | grep -E "(^|/)init$"', shell=True)

            # Mostra tipo e encoding
            console.print("[cyan]→ Verificando tipo de ficheiro...[/cyan]")
            safe_run(f'file {init_file}', shell=True)

            # Mostra primeiras linhas (para confirmar shebang)
            console.print("[cyan]→ Conteúdo inicial do init (máx 10 linhas)...[/cyan]")
            safe_run(f'head -n 10 {init_file}', shell=True)

            # Sanitização: remove BOM e CRLF
            console.print("[blue]→ Removendo BOM e CRLF (normalização universal)...[/blue]")
            safe_run(f"sed -i '1s/^\\xEF\\xBB\\xBF//' {init_file}", shell=True)
            safe_run(f"sed -i 's/\\r$//' {init_file}", shell=True)

            # Confirma permissões
            console.print("[cyan]→ Ajustando permissões de execução...[/cyan]")
            safe_run(f'chmod 0755 {init_file}', shell=True)

            # Segunda verificação do tipo
            console.print("[green]✔ Ficheiro final após normalização:[/green]")
            safe_run(f'file {init_file}', shell=True)

            # Validação do shebang e encoding
            console.print("[blue]→ Testando assinatura e line endings...[/blue]")
            safe_run(f"head -n1 {init_file} | od -c", shell=True)
            safe_run(f"grep -Ua 'bin/sh' {init_file} | head -n1", shell=True)

            console.print("[green]✔ init validado e pronto para inclusão no initramfs[/green]")

            # Criar disco (se não existir)
            data_disk = nfdos_dir / "nfdos_data.img"
            if not data_disk.exists():
                console.print("[cyan]💽 Criando disco persistente (hipocampo físico)...[/cyan]")
                safe_run(f"dd if=/dev/zero of={data_disk} bs=1M count=512", shell=True)
            else:
                console.print("[green]✔ Disco persistente já existe.[/green]")

            time.sleep(5)

            # Testar no QEMU
            bz_image = linux_dir / "arch" / "x86" / "boot" / "bzImage"
            data_disk = nfdos_dir / "nfdos_data.img"

            if bz_image.exists():
                console.print("\n[bold blue]Iniciando QEMU (modo kernel direto)...[/bold blue]")

                # 🧠 Monta a linha base do QEMU
                kernel_params = (
                    "console=ttyS0 earlyprintk=serial,ttyS0,115200 "
                    "keep_bootcon loglevel=8"
                )

                qemu_cmd = (
                    f"qemu-system-x86_64 "
                    f"-machine q35,accel=kvm "
                    f"-cpu qemu64 "
                    f"-kernel {bz_image} "
                    f"-initrd {nfdos_dir}/initramfs.cpio.gz "
                    f"-append '{kernel_params}' "
                    f"-drive file={data_disk},if=virtio,format=raw "
                    f"-m 1024 "
                    f"-nographic "
                    f"-no-reboot"
                )

                # 🚀 Executa o QEMU
                safe_run(qemu_cmd, shell=True)

            else:
                console.print("[red]✗ bzImage não encontrado! Compile o kernel primeiro.[/red]")


        elif choice == "7":
            menu_iso.run()

        elif choice == "0":
            break
        else:
            console.print("[red]Opção inválida![/red]")

        time.sleep(1)

