# ============================================================================
#  FWS — interactive-defaults.ks
#
#  Kickstart de base, lu AUTOMATIQUEMENT par Anaconda quand l'install est
#  lancée en mode interactif (chemin fixe codé en dur dans Anaconda :
#  /usr/share/anaconda/interactive-defaults.ks). Aucun inst.ks= n'est requis.
#
#  RÔLE : finaliser une install « copie du live » (surtout pas Fedora).
#  ----------------------------------------------------------------------------
#  Anaconda n'a AUCUN backend pacman ; son payload par défaut (DNF) poserait
#  des RPM Fedora. Ici le payload est LiveOS, imposé par « anaconda --liveinst »
#  (cf. bloc « Source d'installation » ci-dessous) : il recopie le squashfs du
#  live (= FWS) sur le disque, puis on finalise nous-mêmes (grub, mkinitcpio,
#  bureau) en %post. C'est le modèle « Sabayon » : le système installé EST une
#  copie du live.
#
#  L'utilisateur garde la main dans le GUI sur tout ce qui N'EST PAS fixé ici :
#  partitionnement, fuseau, clavier, langue, création d'utilisateur, mot de
#  passe root, etc.
# ============================================================================

# --- Source d'installation : le payload LiveOS (surtout pas Fedora/DNF) ------
# AUCUNE directive de payload ici, et c'est VOULU. liveinst lance
# « anaconda --liveinst » et anaconda.py teste opts.liveinst AVANT le type du
# payload DBus → il crée TOUJOURS un payload LiveOS et IGNORE tout payload du
# kickstart (un « liveimg » ici serait du code mort — vérifié dans
# pyanaconda/anaconda.py, propriété payload, et reproduit hors VM).
#
# Le payload LiveOS détecte l'image live via /dev/mapper/live-base ou
# /run/rootfsbase (chemins Fedora/dracut, absents d'archiso → c'était le crash
# « SourceSetupError: No Live OS image found! » au démarrage). Le .xinitrc du
# live bind-monte donc /run/archiso/airootfs (squashfs FWS, ro) sur
# /run/rootfsbase AVANT de lancer liveinst : Anaconda monte le loop device et
# rsync son contenu vers la cible = le système installé EST une copie du live,
# puis on finalise en %post (grub, mkinitcpio, bureau, matériel).
# DNF/libdnf5 n'est jamais importé : le module DNF n'est chargé QUE si le
# payload actif est DNF (import lazy dans modules/payloads/payload/factory.py).

# --- Disque : repartir d'un disque PROPRE, même s'il a déjà servi ------------
# Sans ça, une réinstallation sur un disque déjà partitionné (typiquement une
# install FWS précédente : partitions + VG LVM « anaconda_archiso ») pose deux
# problèmes : le partitionnement auto n'a plus d'espace libre, et blivet
# rescanne/auto-active un LVM existant au boot du live → l'installateur se
# comporte mal voire plante au 2e passage (alors qu'un disque vierge passe).
#   zerombr                : réinitialise toute table de partitions invalide
#                            (répond « oui » au lieu de bloquer sur un disque
#                            non reconnu).
#   clearpart --all        : supprime TOUTES les partitions des disques
#                            SÉLECTIONNÉS dans le GUI (l'utilisateur choisit le
#                            disque cible — les autres, ex. disques de jeux, ne
#                            sont pas touchés s'il ne les sélectionne pas).
#   --initlabel            : réécrit une étiquette de disque neuve.
#   --disklabel            : type de table CHOISI SELON LE FIRMWARE par le %pre
#                            plus bas (ne surtout PAS coder en dur) :
#                            • UEFI → gpt : l'ESP peut être créée → grub-install
#                              EFI fonctionne. Forcer « msdos » en UEFI empêchait
#                              l'ESP (→ install NON bootable) et réécrivait la
#                              table pour rien : c'est LE bug corrigé ici.
#                            • BIOS → msdos : core.img se loge dans l'espace
#                              post-MBR (pas de partition BIOS Boot EF02 requise,
#                              qu'Anaconda ne crée pas avec « bootloader --disabled »).
# L'utilisateur garde la main dans le GUI (il peut repasser en manuel), mais le
# DÉFAUT est un disque net → réinstall fiable à chaque fois.
zerombr
# Table de partitions injectée par le %pre (GPT en UEFI, MBR en BIOS).
%include /tmp/fws-clearpart.ks

# --- Bootloader : géré à la main en %post ------------------------------------
# Anaconda lancerait « grub2-install » / « grub2-mkconfig » (binaires Fedora,
# préfixe grub2-) qui n'existent pas dans un rootfs Arch (lequel fournit
# grub-install / grub-mkconfig). On désactive donc l'étape native d'Anaconda.
# L'ESP (UEFI) ou la partition bios_boot (BIOS/GPT) reste créée par le
# partitionnement (auto ou manuel) car la plateforme l'impose.
bootloader --disabled

# Pas de section %packages : le payload LiveOS n'installe aucun paquet
# (il copie une image). Toute installation de paquets se fait en %post.

# --- Récapitulatif avant installation : PAGE GUI dédiée (pas de %pre-install) -
# L'écran « RÉCAPITULATIF AVANT INSTALLATION » est une standalone spoke
# Anaconda (overlay airootfs : pyanaconda/ui/gui/spokes/fws_recap.py,
# postForHub=SummaryHub, priority -10) intercalée ENTRE le hub et l'écran de
# progression : l'utilisateur clique « Commencer l'installation », voit le
# récap (bureau choisi, hostname, disques, GPU, réseau — AUCUNE écriture
# disque à ce stade), et l'installation ne démarre qu'à son clic « Lancer
# l'installation ». L'ancien récap zenity en %pre-install a été abandonné :
# le module scripts tourne avec LC_ALL=C et un env X incertain (zenity 4
# refuse les libellés UTF-8 en locale C → rc=255 pris pour « Annuler » →
# poweroff en plein install au 1er test réel).


# ============================================================================
#  %pre — TABLE DE PARTITIONS SELON LE FIRMWARE
#  Génère /tmp/fws-clearpart.ks (inclus dans la section commandes ci-dessus) :
#  GPT en UEFI (→ ESP créable → grub-install EFI fonctionne), MBR/msdos en BIOS.
#  Les scripts %pre s'exécutent AVANT l'application des commandes du kickstart,
#  donc le %include voit toujours le fichier généré ici.
# ============================================================================
%pre --log=/tmp/fws-pre.log
if [ -d /sys/firmware/efi ]; then
    disklabel=gpt
else
    disklabel=msdos
fi
echo "clearpart --all --initlabel --disklabel=$disklabel" > /tmp/fws-clearpart.ks
%end


# ============================================================================
#  %post --nochroot — s'exécute dans le LIVE, la cible montée sous /mnt/sysroot
#  But : déposer dans la cible ce dont le %post chrooté aura besoin (DNS pour
#  pacman, choix de bureau écrit par l'addon de sélection).
# ============================================================================
%post --nochroot --log=/tmp/fws-post-nochroot.log
set -x

# Selon la version d'Anaconda la cible est sous /mnt/sysroot (récent) ou
# /mnt/sysimage (ancien).
SYSROOT=/mnt/sysroot
[ -d "$SYSROOT" ] || SYSROOT=/mnt/sysimage

# DNS pour que « pacman -S <bureau> » fonctionne dans le chroot.
cp -f /etc/resolv.conf "$SYSROOT/etc/resolv.conf" 2>/dev/null || true

# --- Hostname : valeur saisie dans le champ « Nom de machine » du spoke User --
# Anaconda ne capte PAS le hostname du spoke Réseau (→ /etc/hostname vide). On a
# donc ajouté un champ Hostname au spoke Utilisateur (cf. patch du paquet
# anaconda) : user.py écrit la valeur dans /tmp/fws-hostname (live). On la
# nettoie (caractères de hostname valides) et on l'écrit dans la cible ; défaut
# « fws » si vide/absent → plus jamais de hostname vide ni « archiso ».
HN=""
[ -f /tmp/fws-hostname ] && HN="$(tr -cd 'a-zA-Z0-9._-' < /tmp/fws-hostname)"
[ -n "$HN" ] || HN="fws"
echo "$HN" > "$SYSROOT/etc/hostname"

# Choix du bureau (écrit par l'addon « Choix du bureau », à venir ; valeur lue
# par le %post chrooté ci-dessous). « cli » par défaut si absent.
if [ -f /tmp/fws-desktop ]; then
    cp -f /tmp/fws-desktop "$SYSROOT/tmp/fws-desktop" 2>/dev/null || true
fi

# --- Noyau : archiso RETIRE /boot/vmlinuz-linux du squashfs ------------------
# mkarchiso boote le noyau depuis l'ISO et l'EXCLUT de l'airootfs squashfs (gain
# de place). Conséquence : le payload LiveOS recopie un rootfs SANS noyau →
# « mkinitcpio: /boot/vmlinuz-linux must be readable » puis aucun OS à booter
# (« Operating System not found »). On récupère donc le noyau depuis le média
# booté (/run/archiso/bootmnt/<install_dir>/boot/<arch>/vmlinuz-linux) et on le
# dépose dans la cible. Les modules (/usr/lib/modules) sont, eux, dans le
# squashfs → déjà recopiés. Avec le noyau présent, le %post chrooté peut bâtir
# l'initramfs (mkinitcpio) et GRUB trouve de quoi booter.
SRC_KERN="$(find /run/archiso/bootmnt -name 'vmlinuz-linux' 2>/dev/null | head -1)"
if [ -n "$SRC_KERN" ]; then
    cp -f "$SRC_KERN" "$SYSROOT/boot/vmlinuz-linux"
else
    echo "[FWS] AVERTISSEMENT : noyau vmlinuz-linux introuvable sur le média"
fi
%end


# ============================================================================
#  %post (chroot) — DANS le rootfs FWS recopié. pacman, grub-install,
#  mkinitcpio existent ici : ce sont les outils Arch de l'image copiée.
#  Log persistant : /var/log/fws-post.log sur le système installé.
# ============================================================================
%post --log=/var/log/fws-post.log
set -x

# --- 1) Purge des résidus « live » (modèle Sabayon = live copié tel quel) ----
# Ce qui est propre au live casserait ou pollue le système installé.
rm -f /etc/mkinitcpio.conf.d/archiso.conf
rm -f /etc/systemd/system/getty@tty1.service.d/autologin.conf
for svc in choose-mirror.service pacman-init.service \
           livecd-talk.service livecd-alsa-unmuter.service \
           etc-pacman.d-gnupg.mount; do
    rm -f "/etc/systemd/system/$svc"
    rm -f /etc/systemd/system/*.target.wants/"$svc"
done
# cloud-init (présent dans l'airootfs archiso) : inutile sur un poste installé.
rm -f /etc/systemd/system/cloud-init.target.wants/* 2>/dev/null || true
# Hooks initramfs archiso, s'ils ont été recopiés en tant que paquet.
if pacman -Q mkinitcpio-archiso &>/dev/null; then
    pacman -Rns --noconfirm mkinitcpio-archiso || true
fi

# --- 2) initramfs propre (preset Arch standard, sans archiso) ----------------
# Le live fournit un preset 'archiso' (/etc/mkinitcpio.d/linux.preset qui pointe
# vers conf.d/archiso.conf + hooks archiso) → inadapté à un disque normal. On
# pose un preset Arch standard (config par défaut /etc/mkinitcpio.conf).
cat > /etc/mkinitcpio.d/linux.preset <<'PRESET'
ALL_kver="/boot/vmlinuz-linux"
PRESETS=('default' 'fallback')
default_image="/boot/initramfs-linux.img"
fallback_image="/boot/initramfs-linux-fallback.img"
fallback_options="-S autodetect"
PRESET
# Le partitionnement auto d'Anaconda met « / » sur LVM (/dev/mapper/...-root).
# Sans le hook 'lvm2' dans l'initramfs, le VG n'est pas activé au boot → la
# racine est introuvable → kernel panic. On l'insère avant 'filesystems' s'il
# manque (inoffensif si la racine n'est finalement pas sur LVM).
if ! grep -qE '^HOOKS=.*\blvm2\b' /etc/mkinitcpio.conf; then
    sed -i -E 's/^(HOOKS=\(.*)\bfilesystems\b/\1lvm2 filesystems/' /etc/mkinitcpio.conf
fi
mkinitcpio -P || echo "[FWS] AVERTISSEMENT : mkinitcpio a échoué"

# --- 3) GRUB installé à la main (cf. bootloader --disabled) ------------------
install_grub() {
    if [ -d /sys/firmware/efi ]; then
        # UEFI. efibootmgr crée l'entrée NVRAM « FWS », mais il peut MANQUER de
        # l'airootfs et son install dépend du réseau → on ne BLOQUE pas dessus.
        pacman -Q efibootmgr &>/dev/null || pacman -Sy --noconfirm efibootmgr || true
        # (a) Entrée NVRAM dédiée (best effort, si efibootmgr dispo) :
        grub-install --target=x86_64-efi --efi-directory=/boot/efi \
            --bootloader-id=FWS --recheck || true
        # (b) Chemin de SECOURS EFI/BOOT/BOOTX64.EFI (--removable) : boote SANS
        #     aucune entrée NVRAM. INDISPENSABLE en VM / sans réseau / firmware
        #     qui « oublie » l'entrée — c'est lui qui garantit le 1er boot UEFI.
        grub-install --target=x86_64-efi --efi-directory=/boot/efi \
            --bootloader-id=FWS --removable --recheck
    else
        # BIOS : installer GRUB dans le MBR du DISQUE physique (PAS une partition)
        # portant « / », même quand « / » est sur du LVM (chaîne
        # LV → PV partition → disque). « lsblk -s » descend vers le physique ; on
        # prend la ligne de type « disk ». ATTENTION : « lsblk -s » dessine un
        # ARBRE → les caractères de branche (└─) se collent au chemin (on
        # obtenait disk='-/dev/sda' → « grub-install: cannot find a GRUB drive
        # for `-/dev/sda' »). On EXTRAIT donc le chemin propre avec grep.
        local rootsrc disk
        rootsrc="$(findmnt -no SOURCE / 2>/dev/null)"
        disk="$(lsblk -spno NAME,TYPE "$rootsrc" 2>/dev/null \
                | awk '$2=="disk"{print $1; exit}' | grep -oE '/dev/[a-z0-9]+')"
        [ -n "$disk" ] || { echo "[FWS] Disque BIOS introuvable pour '$rootsrc'"; return 1; }
        grub-install --target=i386-pc --recheck "$disk"
    fi
}
if install_grub; then
    grub-mkconfig -o /boot/grub/grub.cfg || echo "[FWS] grub-mkconfig a échoué"
else
    echo "[FWS] AVERTISSEMENT : grub-install a échoué — bootloader à refaire à la main"
fi

# --- 3bis) Clavier (X11) + LOCALE --------------------------------------------
# CLAVIER : Anaconda passe par localed et n'écrit pas fiablement la disposition X
# sur la CIBLE → SDDM / sessions X en QWERTY US. On CALCULE la disposition CHOISIE
# (kickstart généré, sinon dérivée de la locale via langtable) en XL/XV, réutilisés
# plus bas (00-keyboard.conf pour SDDM/X ET la config Hyprland qui a son propre
# kb_layout). LOCALE : le locale choisi (ex. fr_CH.UTF-8) doit être GÉNÉRÉ —
# Anaconda vient de Fedora (locales pré-générées) et ne lance pas locale-gen →
# sans ça LANG casse et tout retombe en C.
XL=""; XV=""
XKB="$(sed -n "s/.*--xlayouts=//p" /root/anaconda-ks.cfg 2>/dev/null | head -1)"
XKB="${XKB#[\'\"]}"; XKB="${XKB%%[\'\"]*}"; XKB="${XKB%%,*}"   # 1re dispo, ex. « ch (fr) »
if [ -z "$XKB" ]; then
    _loc="$(. /etc/locale.conf 2>/dev/null; printf '%s' "${LANG%%.*}")"   # fr_CH
    _lng="${_loc%%_*}"; _terr="${_loc#*_}"; [ "$_terr" = "$_loc" ] && _terr=""
    [ -n "$_terr" ] && XKB="$(python3 -c "import langtable; k=langtable.list_keyboards(languageId='$_lng', territoryId='$_terr'); print(k[0] if k else '')" 2>/dev/null)"
fi
if [ -n "$XKB" ]; then
    XL="${XKB%%(*}"; XL="${XL%% *}"                              # ch
    case "$XKB" in *'('*')') XV="${XKB#*(}"; XV="${XV%)}" ;; *) XV="" ;; esac   # fr
    install -d /etc/X11/xorg.conf.d
    cat > /etc/X11/xorg.conf.d/00-keyboard.conf <<KBEOF
Section "InputClass"
    Identifier "system-keyboard"
    MatchIsKeyboard "on"
    Option "XkbLayout" "$XL"
    Option "XkbVariant" "$XV"
EndSection
KBEOF
fi

FWSLANG="$(. /etc/locale.conf 2>/dev/null; printf '%s' "${LANG:-}")"
if [ -n "$FWSLANG" ]; then
    _cs="${FWSLANG##*.}"; [ "$_cs" = "$FWSLANG" ] && _cs="UTF-8"
    grep -qE "^[[:space:]]*${FWSLANG}[[:space:]]+${_cs}\b" /etc/locale.gen 2>/dev/null \
        || printf '%s %s\n' "$FWSLANG" "$_cs" >> /etc/locale.gen
    locale-gen || echo "[FWS] locale-gen a échoué pour $FWSLANG"
fi

# --- 4) Bureau choisi : pacman -S du DE (non bloquant si pas de réseau) -------
DESK="cli"
[ -f /tmp/fws-desktop ] && DESK="$(tr -d '[:space:]' < /tmp/fws-desktop)"
DM=""
case "$DESK" in
    kde)      PKGS="plasma-meta sddm konsole dolphin";   DM="sddm" ;;
    gnome)    PKGS="gnome gdm";                          DM="gdm" ;;
    # noto-fonts : KDE l'a via plasma-meta et GNOME a cantarell, mais XFCE et
    # Hyprland ne garantissent AUCUNE police TTF → greeter SDDM/apps illisibles.
    # Hyprland : la stack des raccourcis FWS (mêmes touches que la config
    # i3/sway maison) — dolphin (Super+E), hyprlock (Super+L), grim+slurp+
    # wl-clipboard (captures), playerctl (touches multimédia) — plus la
    # plomberie de bureau : mako+libnotify (notifications), polkit-gnome
    # (agent d'authentification GUI), network-manager-applet (réseau dans le
    # tray), xdg-desktop-portal-hyprland (partage d'écran/portails), gvfs
    # (montage USB via udisks2), ttf-nerd-fonts-symbols (icônes waybar).
    # Son et Bluetooth GARANTIS avec le bureau : la stack PipeWire + le
    # mixeur (pavucontrol) + bluez/blueman partent dans la MÊME transaction
    # pacman que le DE — si le bureau s'installe, ses gestionnaires aussi
    # (fws-setup-hardware les re-propose ensuite en --needed : sans effet
    # s'ils sont déjà là, filet de secours sinon).
    xfce)     PKGS="xfce4 xfce4-goodies sddm noto-fonts pipewire pipewire-pulse wireplumber pavucontrol"; DM="sddm" ;;
    hyprland) PKGS="hyprland kitty wofi waybar sddm noto-fonts dolphin kio-extras udisks2 hyprlock grim slurp wl-clipboard playerctl mako libnotify polkit-gnome network-manager-applet xdg-desktop-portal-hyprland ttf-nerd-fonts-symbols pipewire pipewire-alsa pipewire-pulse wireplumber pavucontrol bluez bluez-utils blueman"; DM="sddm" ;;
    # i3 : session X11 → COMPATIBLE VR (SteamVR ne marche pas sous Wayland).
    # xorg-server est requis (SDDM ne le tire pas) ; maim+xclip = captures X11,
    # dunst = notifications X11 (équivalent de mako), i3lock = verrouillage.
    # fws-vr-setup (Super+Shift+V ou menu) installe les drivers du casque.
    i3)       PKGS="i3-wm i3lock xorg-server polybar picom rofi kitty dolphin kio-extras udisks2 sddm noto-fonts ttf-nerd-fonts-symbols maim xclip dunst libnotify polkit-gnome network-manager-applet playerctl brightnessctl pipewire pipewire-alsa pipewire-pulse wireplumber pavucontrol bluez bluez-utils blueman"; DM="sddm" ;;
    cli|*)    PKGS="" ;;
esac
# Navigateur de base ajouté DÈS QU'un bureau est choisi (jamais en CLI).
# + python-gobject : fenêtre de bienvenue fws-hello (GTK3 vient avec Firefox)
# + pacman-contrib : checkupdates/paccache (indicateur de MàJ + fws-update)
[ -n "$PKGS" ] && PKGS="$PKGS firefox python-gobject pacman-contrib"
if [ -n "$PKGS" ]; then
    pacman-key --init            &>/dev/null || true
    pacman-key --populate archlinux &>/dev/null || true

    # Script de RATTRAPAGE généré avec les valeurs de CE choix : si l'install
    # du bureau échoue (réseau/miroirs), l'utilisateur la rejoue en une
    # commande depuis le système installé. --needed → inoffensif si déjà fait.
    cat > /usr/local/bin/fws-desktop-retry <<RETRYEOF
#!/bin/bash
# Généré par l'installateur FWS — (ré)installe le bureau « $DESK ».
set -u
[ "\$(id -u)" -eq 0 ] || exec sudo "\$0" "\$@"
echo "==> Installation du bureau $DESK…"
pacman -Syy --noconfirm --needed $PKGS || { echo "Échec (réseau ?) — réessayez."; exit 1; }
[ -n "$DM" ] && systemctl enable "$DM"
systemctl set-default graphical.target
rm -f /var/lib/fws/desktop-failed
[ -f /etc/motd ] && grep -q fws-desktop-retry /etc/motd && rm -f /etc/motd
echo "==> Bureau installé ✔ — redémarrez (reboot) pour arriver sur l'écran de connexion."
RETRYEOF
    chmod 755 /usr/local/bin/fws-desktop-retry

    # Le réseau peut mettre quelques secondes à monter dans l'environnement
    # d'installation : on attend la résolution DNS avant le premier essai,
    # puis on tente pacman jusqu'à 3 fois (miroir capricieux ≠ échec définitif).
    for _i in 1 2 3 4 5 6 7 8 9 10; do
        getent hosts geo.mirror.pkgbuild.com >/dev/null 2>&1 && break
        sleep 3
    done
    _DE_OK=""
    for _try in 1 2 3; do
        pacman -Sy --noconfirm --needed $PKGS && { _DE_OK=1; break; }
        echo "[FWS] installation du bureau : tentative $_try échouée — nouvel essai dans 15 s…"
        sleep 15
    done
    if [ -n "$_DE_OK" ]; then
        [ -n "$DM" ] && systemctl enable "$DM" || true
        systemctl set-default graphical.target || true
        # SDDM (KDE / XFCE / Hyprland) : pavé numérique + écran de connexion FWS.
        # Le thème « fws » (livré par l'airootfs → recopié par le payload dans
        # /usr/share/sddm/themes/fws) est en pur QtQuick/Controls Basic :
        # qt6-declarative, dépendance de sddm, suffit → même écran soigné pour
        # les 3 DE SANS paquet de thème supplémentaire (Breeze n'existe qu'avec
        # plasma). Accent adapté au bureau via theme.conf.user (mécanisme de
        # surcharge standard de SDDM, lu par-dessus theme.conf du thème).
        if [ "$DM" = "sddm" ]; then
            install -d /etc/sddm.conf.d
            cat > /etc/sddm.conf.d/10-fws.conf <<'SDDMEOF'
[General]
Numlock=on

[Theme]
Current=fws
SDDMEOF
            case "$DESK" in
                xfce)     _ACCENT="#16a085" ;;   # sarcelle (assorti à XFCE)
                hyprland) _ACCENT="#89b4fa" ;;   # bleu Catppuccin (assorti à Hyprland)
                *)        _ACCENT="#3daee9" ;;   # bleu Breeze (KDE, défaut)
            esac
            if [ -d /usr/share/sddm/themes/fws ]; then
                printf '[General]\naccent=%s\n' "$_ACCENT" \
                    > /usr/share/sddm/themes/fws/theme.conf.user
            else
                echo "[FWS] thème SDDM fws introuvable — thème par défaut conservé"
                sed -i '/^Current=fws$/d' /etc/sddm.conf.d/10-fws.conf
            fi
        fi
        # GDM (GNOME) : « la même chose » autant que possible — le greeter de
        # GDM EST GNOME Shell, il ne se thème pas comme SDDM. On passe par
        # dconf (base système « gdm ») : bannière d'accueil FWS, horloge avec
        # date complète, pavé numérique allumé — même confort qu'avec SDDM.
        if [ "$DM" = "gdm" ]; then
            install -d /etc/dconf/profile /etc/dconf/db/gdm.d
            cat > /etc/dconf/profile/gdm <<'GDMEOF'
user-db:user
system-db:gdm
file-db:/usr/share/gdm/greeter-dconf-defaults
GDMEOF
            cat > /etc/dconf/db/gdm.d/10-fws <<'GDMEOF'
[org/gnome/login-screen]
banner-message-enable=true
banner-message-text='Bienvenue sur FWS'

[org/gnome/desktop/interface]
clock-show-date=true
clock-show-weekday=true

[org/gnome/desktop/peripherals/keyboard]
numlock-state=true
remember-numlock-state=false
GDMEOF
            dconf update || echo "[FWS] dconf update a échoué (bannière GDM à refaire)"
        fi
        # Hyprland en VM : sur GPU virtuel (VMware/VirtualBox) le compositeur
        # crashe au lancement → SDDM « remet au login ». On le lance via un
        # wrapper qui force le rendu LOGICIEL UNIQUEMENT en VM (systemd-detect-virt)
        # ; sur un vrai GPU le rendu matériel est conservé.
        if [ "$DESK" = "hyprland" ]; then
            cat > /usr/local/bin/fws-hyprland <<'HYEOF'
#!/bin/sh
if systemd-detect-virt --quiet 2>/dev/null; then
    # GPU virtuel (VMware vmwgfx…) : on FORCE le chemin d'affichage 100% logiciel.
    # La PIÈCE MAÎTRESSE est MESA_LOADER_DRIVER_OVERRIDE=kms_swrast : elle force
    # Mesa à allouer le GBM/EGL via kms_swrast (rendu logiciel dans les « dumb
    # buffers » KMS) AU LIEU du pilote vmwgfx (qui ne fournit pas le GBM dont
    # aquamarine a besoin → « CBackend::create() failed »). + llvmpipe pour le GL.
    export MESA_LOADER_DRIVER_OVERRIDE=kms_swrast
    export GALLIUM_DRIVER=llvmpipe LIBGL_ALWAYS_SOFTWARE=1
    export WLR_RENDERER_ALLOW_SOFTWARE=1 WLR_NO_HARDWARE_CURSORS=1
    export AQ_NO_ATOMIC=1
fi
# Hyprland ≥ 0.53 : start-hyprland est le lanceur officiel (prépare la
# session/env systemd) — sans lui, bandeau « started without start-hyprland ».
if command -v start-hyprland >/dev/null 2>&1; then
    exec start-hyprland "$@"
fi
exec Hyprland "$@"
HYEOF
            chmod 755 /usr/local/bin/fws-hyprland
            if [ -f /usr/share/wayland-sessions/hyprland.desktop ]; then
                sed -i 's|^Exec=.*|Exec=/usr/local/bin/fws-hyprland|' \
                    /usr/share/wayland-sessions/hyprland.desktop
            fi
            # Bluetooth prêt au 1er démarrage (bluez vient d'être installé
            # avec le bureau ; fws-setup-hardware le refait — idempotent).
            systemctl enable bluetooth.service 2>/dev/null || true
        fi
        if [ "$DESK" = "i3" ]; then
            systemctl enable bluetooth.service 2>/dev/null || true
            # Icône du lanceur « Installation VR » (casque) visible dans rofi.
            gtk-update-icon-cache -f /usr/share/icons/hicolor 2>/dev/null || true
        fi
    else
        echo "[FWS] Bureau '$DESK' NON installé après 3 tentatives (réseau/miroirs ?)."
        echo "[FWS] Rattrapage sur le système installé : sudo fws-desktop-retry"
        mkdir -p /var/lib/fws
        echo "$DESK" > /var/lib/fws/desktop-failed
        # Le premier login (console) explique quoi faire — le motd est retiré
        # par fws-desktop-retry une fois le bureau posé.
        cat > /etc/motd <<'MOTD'

  ⚠  FWS : l'installation du bureau a échoué (réseau indisponible pendant
     l'installation). Le système fonctionne, mais en console.

     Une fois le réseau branché, lancez :   sudo fws-desktop-retry
     puis redémarrez : le bureau choisi sera installé et activé.

MOTD
    fi
fi

# --- 4quater) ADN FWS : détection matériel + drivers + stack « Windows » ------
# Script dédié (NON bloquant ; réseau requis) : drivers GPU détectés via lspci +
# outils invité VM, son/micro/casque (PipeWire), Bluetooth, Podman, et — si un
# bureau est choisi — Steam, Wine, VR (Monado/SteamVR), winboat-bin (apps
# Windows). C'est le cœur « remplacement de Windows » de FWS.
if [ -x /usr/local/bin/fws-setup-hardware ]; then
    /usr/local/bin/fws-setup-hardware "$DESK" || true
fi

# --- Config Hyprland (si choisi) : clavier + apps + waybar -------------------
# Hyprland (Wayland) NE lit PAS /etc/X11/xorg.conf.d/00-keyboard.conf : sa
# disposition est dans SA config (input { kb_layout }). Sans config il démarre nu
# (QWERTY US, aucune touche utile). On déploie une config FWS (template +
# clavier XL/XV injecté) dans /etc/skel ET le home de chaque utilisateur déjà
# créé par Anaconda (le %post tourne APRÈS la création de l'utilisateur).
if [ "$DESK" = "hyprland" ] && [ -f /usr/local/share/fws/hyprland.conf.tmpl ]; then
    sed -e "s/__KB_LAYOUT__/${XL:-us}/" -e "s/__KB_VARIANT__/${XV}/" \
        /usr/local/share/fws/hyprland.conf.tmpl > /tmp/fws-hyprland.conf
    install -Dm644 /tmp/fws-hyprland.conf /etc/skel/.config/hypr/hyprland.conf
    # Waybar FWS : barre assortie + bouton « ⌨ Raccourcis » (fws-keys,
    # aussi sur SUPER+K) qui liste les binds RÉELS chargés par Hyprland
    # (hyprctl binds -j) — les descriptions viennent des bindd de la config.
    install -Dm644 /usr/local/share/fws/waybar-config.json /etc/skel/.config/waybar/config
    install -Dm644 /usr/local/share/fws/waybar-style.css /etc/skel/.config/waybar/style.css
    # wofi : style du menu d'applications (Super+R) — le panneau « Raccourcis »
    # a son propre style (wofi-keys.css), passé en --style par fws-keys.
    install -Dm644 /usr/local/share/fws/wofi-config /etc/skel/.config/wofi/config
    install -Dm644 /usr/local/share/fws/wofi-style.css /etc/skel/.config/wofi/style.css
    while IFS=: read -r _u _x _uid _g _gec _home _sh; do
        [ "$_uid" -ge 1000 ] && [ "$_uid" -le 60000 ] && [ -d "$_home" ] || continue
        install -Dm644 /tmp/fws-hyprland.conf "$_home/.config/hypr/hyprland.conf"
        install -Dm644 /usr/local/share/fws/waybar-config.json "$_home/.config/waybar/config"
        install -Dm644 /usr/local/share/fws/waybar-style.css "$_home/.config/waybar/style.css"
        install -Dm644 /usr/local/share/fws/wofi-config "$_home/.config/wofi/config"
        install -Dm644 /usr/local/share/fws/wofi-style.css "$_home/.config/wofi/style.css"
        chown "$_u": "$_home/.config" 2>/dev/null || true
        chown -R "$_u": "$_home/.config/hypr" "$_home/.config/waybar" \
                        "$_home/.config/wofi" 2>/dev/null || true
    done < /etc/passwd
    rm -f /tmp/fws-hyprland.conf
fi

# --- Config i3 (si choisi) : raccourcis FWS + barre + autostart -------------
# Pas d'injection clavier ici : les sessions X11 lisent la disposition dans
# /etc/X11/xorg.conf.d/00-keyboard.conf, écrite à l'étape 3bis.
if [ "$DESK" = "i3" ] && [ -f /usr/local/share/fws/i3-config ]; then
    install -Dm644 /usr/local/share/fws/i3-config /etc/skel/.config/i3/config
    # Polybar (clone de la waybar) + picom (coins arrondis) : même rendu
    # visuel que la session Hyprland FWS.
    install -Dm644 /usr/local/share/fws/polybar-config.ini /etc/skel/.config/polybar/config.ini
    install -Dm644 /usr/local/share/fws/picom.conf /etc/skel/.config/picom.conf
    # rofi : menu d'applications au look FWS (équivalent du wofi d'Hyprland).
    install -Dm644 /usr/local/share/fws/rofi-config.rasi /etc/skel/.config/rofi/config.rasi
    while IFS=: read -r _u _x _uid _g _gec _home _sh; do
        [ "$_uid" -ge 1000 ] && [ "$_uid" -le 60000 ] && [ -d "$_home" ] || continue
        install -Dm644 /usr/local/share/fws/i3-config "$_home/.config/i3/config"
        install -Dm644 /usr/local/share/fws/polybar-config.ini "$_home/.config/polybar/config.ini"
        install -Dm644 /usr/local/share/fws/picom.conf "$_home/.config/picom.conf"
        install -Dm644 /usr/local/share/fws/rofi-config.rasi "$_home/.config/rofi/config.rasi"
        chown "$_u": "$_home/.config" 2>/dev/null || true
        chown -R "$_u": "$_home/.config/i3" "$_home/.config/polybar" \
                        "$_home/.config/rofi" "$_home/.config/picom.conf" 2>/dev/null || true
    done < /etc/passwd
fi

# --- 4bis) Sudo : l'utilisateur créé doit pouvoir administrer -----------------
# Arch laisse « %wheel » COMMENTÉ dans sudoers → même un membre de wheel ne peut
# pas sudo. On active le groupe wheel (drop-in) ET on y ajoute tous les
# utilisateurs HUMAINS (UID 1000-60000) créés par Anaconda → ils sont sudoers.
install -d -m 750 /etc/sudoers.d
printf '%%wheel ALL=(ALL:ALL) ALL\n' > /etc/sudoers.d/10-fws-wheel
chmod 440 /etc/sudoers.d/10-fws-wheel
while IFS=: read -r _u _x _uid _rest; do
    if [ "$_uid" -ge 1000 ] && [ "$_uid" -le 60000 ]; then
        usermod -aG wheel "$_u" 2>/dev/null || true
    fi
done < /etc/passwd

# --- 4ter) Branding FWS sur le système installé -------------------------------
# Le hook os-release du build n'est PAS sur la cible et « pacman -S » a pu
# remettre l'os-release d'Arch → d'où « Arch Linux » au menu GRUB, le logo Arch
# sur l'écran de connexion (GDM lit os-release LOGO) et le nom « Arch ». On FORCE
# donc l'os-release FWS (+ lsb-release + GRUB_DISTRIBUTOR), on RÉGÉNÈRE le menu
# GRUB (10_linux lit le NAME d'os-release), et on retire le motd « live ».
if [ -f /usr/local/share/fws/os-release ]; then
    cp -f /usr/local/share/fws/os-release /usr/lib/os-release
    ln -sf ../usr/lib/os-release /etc/os-release
fi
if [ -f /etc/lsb-release ]; then
    sed -i 's/^DISTRIB_ID=.*/DISTRIB_ID=FWS/; s/^DISTRIB_DESCRIPTION=.*/DISTRIB_DESCRIPTION="FWS Linux"/' \
        /etc/lsb-release
fi
if grep -q '^GRUB_DISTRIBUTOR=' /etc/default/grub 2>/dev/null; then
    sed -i 's/^GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR="FWS"/' /etc/default/grub
else
    echo 'GRUB_DISTRIBUTOR="FWS"' >> /etc/default/grub
fi
grub-mkconfig -o /boot/grub/grub.cfg 2>/dev/null || true
# motd « live » (texte inadapté + codes ANSI bruts affichés crus par GDM) —
# SAUF si c'est notre message « fws-desktop-retry » (échec d'install du
# bureau), qui doit survivre jusqu'au rattrapage.
grep -q fws-desktop-retry /etc/motd 2>/dev/null || rm -f /etc/motd

# --- 4quinquies) Pare-feu par défaut -------------------------------------------
# firewalld est dans l'IMAGE (packages.x86_64) → recopié par le payload,
# activation possible HORS LIGNE. Zone par défaut « public » : entrées
# bloquées, sortant libre — le comportement attendu d'un poste de travail.
# GUI incluse dans le paquet (firewall-config) ; KDE a en plus plasma-firewall.
systemctl enable firewalld.service 2>/dev/null || true

# --- 4quinquies-bis) Horloge juste : synchronisation NTP -----------------------
# Sans NTP l'horloge dérive (TLS/pacman finissent par râler, et un utilisateur
# venant de Windows s'attend à une heure exacte). systemd-timesyncd est dans
# l'image ; on l'ACTIVE explicitement — les symlinks d'activation hérités du
# live étaient des FICHIERS ordinaires (artefact de checkout) que systemd
# ignore (« not a symlink »), corrigés côté live mais on assure ici quoi
# qu'il arrive sur le système installé.
systemctl enable systemd-timesyncd.service 2>/dev/null || true

# NB Récupération : l'entrée GRUB « Réparer FWS » (générée par
# /etc/grub.d/42_fws-recovery lors des grub-mkconfig ci-dessus) boote
# systemd.unit=fws-recovery.target → fws-recovery-boot.service prend tty1 et
# lance l'application de réparation. RIEN à activer : le service n'a pas de
# [Install] (son Conflicts=getty@tty1 ne doit jamais entrer dans un boot
# normal), la target le tire par Requires. Dans le bureau, le lanceur
# « Récupération FWS » (fws-recovery.desktop, polkit) fait le même travail.

# --- 5) Sécurité : verrouiller root s'il est resté SANS mot de passe ----------
# L'airootfs live a souvent un root sans mot de passe ; si l'utilisateur n'en a
# pas défini dans le GUI, on verrouille plutôt que de laisser le compte ouvert.
if passwd -S root 2>/dev/null | grep -qE '\bNP\b'; then
    passwd -l root || true
fi

# --- 6) DNS du système installé : NetworkManager + systemd-resolved ----------
# Le live utilise systemd-resolved (/etc/resolv.conf → stub 127.0.0.53). L'ANCIEN
# « rm /etc/resolv.conf » comptait sur NM pour recréer le fichier — MAIS avec
# systemd-resolved actif, NM ne réécrit PAS resolv.conf (il pousse les DNS vers
# resolved). Sans le lien, la résolution est MORTE → « Limited Connectivity » /
# Firefox « Server Not Found » (le réseau marche, le DNS non). Fix robuste :
#  - resolv.conf → stub systemd-resolved,
#  - service systemd-resolved activé,
#  - on FORCE NM à utiliser resolved (dns=systemd-resolved) → il lui fournit les
#    DNS DHCP, la résolution marche dès le 1er boot.
rm -f /tmp/fws-desktop 2>/dev/null || true
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
systemctl enable systemd-resolved.service 2>/dev/null || true
install -d /etc/NetworkManager/conf.d
printf '[main]\ndns=systemd-resolved\n' > /etc/NetworkManager/conf.d/dns.conf
%end


# ============================================================================
#  %post --nochroot (FINAL) — exfiltre le log du %post chrooté vers le LIVE.
#  À ce stade la cible est ENCORE montée sous /mnt/sysroot (l'unmount n'a pas
#  encore eu lieu). On copie /var/log/fws-post.log (résultat de grub-install /
#  mkinitcpio) vers le live /tmp pour que le harnais de debug (.xinitrc)
#  l'affiche SANS avoir à remonter le disque démonté — c'est ce log qui dit si
#  le disque va booter.
# ============================================================================
%post --nochroot
SYSROOT=/mnt/sysroot
[ -d "$SYSROOT" ] || SYSROOT=/mnt/sysimage
cp -f "$SYSROOT/var/log/fws-post.log" /tmp/fws-post-chroot.log 2>/dev/null || true
%end
