#!/usr/bin/env python3
"""
💾 Módulo de Inicialização de Disco — Neurotron V0.1 (atualizado)
Detecta, avalia, prepara e monta o disco persistente do NFDOS.
- Não formata discos que já contenham um filesystem conhecido, a menos que forçado.
- Forçar formatação:
    * EXPORT: export NFDOS_FORCE_FORMAT=1 (no ambiente do initramfs, se aplicável)
    * Kernel cmdline: adicionar `nfdos_force_format=1` ao -append do QEMU
"""

import os
import subprocess
from pathlib import Path
from rich.console import Console
if __name__ == "__main__" and __package__ is None:
    import sys
    from pathlib import Path
    sys.path.append(str(Path(__file__).resolve().parents[1]))
    __package__ = "neurotron_core"

from .neurotron_config import (
    MOUNT_POINT, DISK_CANDIDATES
)

console = Console()

def run(cmd: list[str]) -> bool:
    """Executa comando silenciosamente (retorna True se OK)."""
    try:
        subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
        return True
    except (subprocess.CalledProcessError, FileNotFoundError):
        return False


def detect_disk() -> str | None:
    """Procura por um dispositivo de disco válido (por ordem em DISK_CANDIDATES)."""
    for dev in DISK_CANDIDATES:
        p = Path(dev)
        if p.exists():
            console.print(f"[cyan]🔍 Detetado disco:[/] {dev}")
            return dev
    console.print("[yellow]⚠️ Nenhum disco detectado.[/yellow]")
    return None


def blkid_check(device: str) -> str | None:
    """Tenta obter tipo com blkid (se disponível)."""
    try:
        out = subprocess.run(["blkid", device], stdout=subprocess.PIPE, text=True, check=False)
        return out.stdout.strip() if out.stdout else None
    except FileNotFoundError:
        return None


def read_sig(device: str, size: int = 2048) -> bytes | None:
    """Lê os primeiros `size` bytes do device (se possível)."""
    try:
        with open(device, "rb") as f:
            return f.read(size)
    except Exception:
        return None


def detect_fs_by_magic(device: str) -> str | None:
    """
    Detecta assinaturas simples:
    - ext4 superblock magic (0xEF53) @ offset 1024 + 56 = 1080
    - NTFS -> 'NTFS    ' @ offset 3
    - FAT32 -> 'FAT32' nos offsets típicos do boot sector
    - MBR partition table signature 0x55AA @ offset 510-511
    Retorna string com o sistema ou None.
    """
    buf = read_sig(device, size=4096)
    if not buf:
        return None

    # MBR signature
    if len(buf) >= 512 and buf[510:512] == b'\x55\xAA':
        # detecta tabela de partições existente (MBR)
        return "mbr-partition-table"

    # ext magic at 1024+56 = 1080
    if len(buf) >= 1082 and buf[1080:1082] == b'\x53\xEF':
        return "ext (superblock)"

    # NTFS signature at offset 3 (ASCII "NTFS    ")
    if len(buf) >= 11 and buf[3:11] == b'NTFS    ':
        return "ntfs"

    # FAT32 signature at offset 82 or boot sector strings containing FAT
    if b"FAT32" in buf or b"FAT16" in buf or b"FAT12" in buf:
        return "fat"

    return None


def parse_cmdline_flag() -> bool:
    """Lê /proc/cmdline para a flag nfdos_force_format=1"""
    try:
        with open("/proc/cmdline", "r") as f:
            cmd = f.read()
        return "nfdos_force_format=1" in cmd.split()
    except Exception:
        return False

def which(prog: str) -> str | None:
    for p in os.environ.get("PATH", "/sbin:/bin:/usr/sbin:/usr/bin").split(":"):
        cand = Path(p) / prog
        if cand.exists() and os.access(cand, os.X_OK):
            return str(cand)
    return None

def format_ext4(device: str, label: str = "NFDOS_DATA") -> bool:
    """Formata o dispositivo com ext4, recolhendo logs de erro detalhados (BusyBox-safe)."""
    mke2fs = which("mke2fs")
    mkfs_ext4 = which("mkfs.ext4")
    mkfs = which("mkfs")

    candidates = []

    if mkfs_ext4:
        candidates.append(([mkfs_ext4, "-F", "-L", label, device], "mkfs.ext4"))
    if mke2fs:
        # o BusyBox mke2fs não aceita '-t', por isso ajustaremos dentro do loop
        candidates.append(([mke2fs, "-F", "-t", "ext4", "-L", label, device], "mke2fs"))
    if mkfs:
        candidates.append(([mkfs, "-t", "ext4", "-F", "-L", label, device], "mkfs"))

    if not candidates:
        console.print("[red]❌ Nenhum utilitário mkfs disponível no initramfs![/red]")
        return False

    for cmd, name in candidates:
        console.print(f"[yellow]⚙️ Formatando {device} com {name}...[/yellow]")

        # 👉 se for o BusyBox mke2fs, removemos o argumento -t
        if name == "mke2fs":
            cmd = [c for c in cmd if c != "-t" and c != "ext4"]

        try:
            result = subprocess.run(
                cmd,
                text=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                check=True,
            )
            if result.stdout:
                console.print(result.stdout.strip())
            console.print(f"[green]✔ Formatação concluída com {name}.[/green]")
            return True

        except subprocess.CalledProcessError as e:
            console.print(f"[red]❌ {name} falhou (código {e.returncode}).[/red]")
            if e.stdout:
                console.print(f"[cyan]📜 STDOUT:[/cyan]\n{e.stdout.strip()}")
            if e.stderr:
                console.print(f"[magenta]⚠️ STDERR:[/magenta]\n{e.stderr.strip()}")

    console.print("[red]❌ Nenhum método de formatação teve sucesso.[/red]")
    console.print("[cyan]🧠 Sugestão:[/] verifique se o kernel suporta EXT4 e se o BusyBox inclui mke2fs.")
    return False


def ensure_fs(device: str) -> bool:
    """
    Verifica se existe sistema de ficheiros.
    Se não existir e houver confirmação/flag, formata ext4 (ou fallback via mke2fs).
    """
    # 1️⃣ tentativa rápida com blkid
    info = blkid_check(device)
    if info:
        console.print(f"[green]🧠 Disco já formatado (blkid):[/] {info}")
        return True

    # 2️⃣ fallback por leituras de assinatura
    sig = detect_fs_by_magic(device)
    if sig:
        console.print(f"[yellow]⚠ Assinatura detectada no disco:[/] {sig}")
        console.print("[red]❗ O disco contém dados ou partições existentes. Abortando formatação.[/red]")
        return False

    # 3️⃣ se nada detectado — disco virgem
    forced_env = os.environ.get("NFDOS_FORCE_FORMAT") == "1"
    forced_cmd = parse_cmdline_flag()

    if not (forced_env or forced_cmd):
        console.print("[yellow]⚠ Disco parece virgem, mas não há confirmação para formatar.[/yellow]")
        console.print("Use `nfdos_force_format=1` no kernel cmdline ou export NFDOS_FORCE_FORMAT=1")
        console.print("para permitir formatação automática.")
        return False

    # 4️⃣ tentar formatação
    console.print(f"[yellow]⚙️ Forçando formatação de {device} como ext4 (FLAG DETETADA)...[/yellow]")

    ok = format_ext4(device)
    if ok:
        console.print("[green]✔ Formatação concluída com sucesso.[/green]")
        return True

    # 5️⃣ se nada funcionou
    console.print("[red]❌ Falha na formatação.[/red]")
    console.print("[cyan]🧠 Sugestão:[/] verifique se o kernel inclui suporte para EXT4 ou se o mkfs/mke2fs está embutido no BusyBox.")
    return False


def mount_disk(device: str) -> bool:
    """Monta o disco no ponto esperado (retorna True se OK)."""
    os.makedirs(MOUNT_POINT, exist_ok=True)
    return run(["mount", device, MOUNT_POINT])


def debug_env():
    """Mostra informações úteis quando nenhum disco é detectado (ou para debug)."""
    console.print("[yellow]🩻 DEBUG: listando /dev/* e últimas mensagens do kernel[/yellow]")
    devs = sorted(Path("/dev").glob("*"))
    console.print("📂 Dispositivos disponíveis:", ", ".join([d.name for d in devs if d.is_char_device() or d.is_block_device()]))
    os.system("dmesg | tail -n 20 || echo '(dmesg não disponível)'")
    console.print("[yellow]───────────────────────────────[/yellow]")
    os.system("echo '--- /proc/partitions ---'; cat /proc/partitions || true")
    os.system("echo '--- dmesg | grep -i virtio ---'; dmesg | grep -i virtio || true")
    console.print("[yellow]───────────────────────────────[/yellow]")


def initialize_persistence():
    """Fluxo completo de inicialização do hipocampo físico."""
    device = detect_disk()
    if not device:
        debug_env()
        console.print("[red]❌ Nenhum disco físico encontrado — usando modo RAM.[/red]")
        return False

    if not ensure_fs(device):
        console.print("[red]❌ Preparação do sistema de ficheiros foi interrompida.[/red]")
        return False

    if not mount_disk(device):
        console.print("[red]❌ Falha ao montar disco.[/red]")
        return False

    console.print(f"[green]✔ Disco montado em:[/] {MOUNT_POINT}")

    telemetry_file = Path("/opt/kernel/neurotron/data/telemetry.json")
    telemetry_file.parent.mkdir(parents=True, exist_ok=True)
    if not telemetry_file.exists():
        telemetry_file.write_text("[]")


    for d in ["data", "logs", "dna"]:
        Path(MOUNT_POINT, d).mkdir(parents=True, exist_ok=True)
    Path(MOUNT_POINT, "DNA_ID").write_text("NEUROTRON_HIPOCAMPUS_V1\n")

    console.print("[cyan]👉 Hipocampo físico inicializado com sucesso.[/cyan]")
    return True


if __name__ == "__main__":
    initialize_persistence()
