//! `hammer-recover` — auto-recuperación de upgrades al **arranque** (E4 / refinamiento #4b).
//!
//! El producto NO lleva el CLI `hammer` completo; este mini-binario (estático musl) es lo único que el
//! sistema instalado necesita para auto-sanar un upgrade interrumpido. El wrapper `/sbin/init` lo corre
//! **tras montar `/store` y `/var/lib/hammer`** y **antes** de incarnar arje-zero:
//!
//! - Sin intento pendiente ⇒ no-op (el caso normal).
//! - Con un `pending.json` (un `hammer upgrade apply` cortado por un apagón/reinicio): intenta
//!   **completar** (roll-forward, re-ejecuta el plan idempotente + commitea); si no puede (p.ej. el árbol
//!   ya no está en `/store`), **deshace** (roll-back) para dejar el FHS consistente. En cualquier caso el
//!   sistema arranca en un estado coherente, no a medias.
//!
//! Encaja con el modelo de generaciones **in-place** (el FHS es la generación viva): no hay menú de
//! generaciones tipo NixOS que seleccionar, sino una reparación determinista del estado a medias.
//!
//! Paths del producto (overridables por entorno para tests):
//!   `HAMMER_RECOVER_ROOT=/`  `HAMMER_RECOVER_STORE=/store`
//!   `HAMMER_RECOVER_STATE=/var/lib/hammer/upgrades`  `HAMMER_RECOVER_JOURNAL=/var/lib/hammer/journal`
//! Flag: `--rollback` fuerza deshacer en vez de completar.
//!
//! NUNCA sale con código ≠0 por un fallo de recuperación: es un hook de arranque, no debe abortar el
//! boot. Reporta por consola y deja que arje-zero siga (con el estado más consistente que logró).

use std::path::PathBuf;

fn env_path(key: &str, default: &str) -> PathBuf {
    std::env::var(key).map(PathBuf::from).unwrap_or_else(|_| PathBuf::from(default))
}

fn main() {
    let force_rollback = std::env::args().skip(1).any(|a| a == "--rollback");
    let root = env_path("HAMMER_RECOVER_ROOT", "/");
    let store = env_path("HAMMER_RECOVER_STORE", "/store");
    let state = env_path("HAMMER_RECOVER_STATE", "/var/lib/hammer/upgrades");
    let journal_dir = env_path("HAMMER_RECOVER_JOURNAL", "/var/lib/hammer/journal");

    match hammer_upgrade::pending(&state) {
        Ok(None) => {
            println!("hammer-recover: sin upgrade interrumpido");
            return;
        }
        Ok(Some(p)) => {
            println!("hammer-recover: upgrade interrumpido (generación {}) — recuperando", p.id);
        }
        Err(e) => {
            eprintln!("hammer-recover: no pude leer el estado de upgrades: {e}");
            return;
        }
    }

    let journal = hammer_journal::Journal::open(&journal_dir).ok();
    let j = journal.as_ref();

    if force_rollback {
        match hammer_upgrade::recover(&store, &root, &state, j, true) {
            Ok(r) => println!("hammer-recover: DESHECHO (generación {} descartada)", r.generation),
            Err(e) => eprintln!("hammer-recover: rollback falló: {e}"),
        }
        return;
    }

    // Optimista: completar el upgrade. Si el roll-forward falla, deshacer ⇒ FHS consistente igual.
    match hammer_upgrade::recover(&store, &root, &state, j, false) {
        Ok(r) => println!("hammer-recover: COMPLETADO (generación {})", r.generation),
        Err(e) => {
            eprintln!("hammer-recover: roll-forward falló ({e}); deshaciendo para dejar el FHS consistente");
            match hammer_upgrade::recover(&store, &root, &state, j, true) {
                Ok(r) => println!("hammer-recover: DESHECHO tras fallo (generación {})", r.generation),
                Err(e2) => eprintln!("hammer-recover: rollback de respaldo también falló: {e2}"),
            }
        }
    }
}
