#!/usr/bin/env bash
# ╔══════════════════════════════════════════════════════════════════════════╗
# ║  build.sh – Compilation + installation de TranscribeStation             ║
# ║  JT-Tools by Johnny · H3Campus · Mars 2026                              ║
# ╚══════════════════════════════════════════════════════════════════════════╝
#
# Usage :
#   ./build.sh                   Build Linux + raccourci GNOME (défaut)
#   ./build.sh --linux           Build Linux uniquement
#   ./build.sh --windows         Génère build_windows.bat (cross depuis Linux)
#   ./build.sh --both            Linux + Windows
#   ./build.sh --no-install      Build sans créer de raccourcis
#   ./build.sh --install-only    Raccourci seulement (binaire déjà compilé)
#   ./build.sh --uninstall       Supprime le raccourci GNOME
#   ./build.sh --clean           Supprime build/ dist/ icon.*
#   ./build.sh --help            Affiche cette aide
#
set -euo pipefail
IFS=$'\n\t'

# ── Constantes ─────────────────────────────────────────────────────────────────
APP_NAME="TranscribeStation"
APP_VERSION="1.0.0"
APP_COMMENT="Gestionnaire de transcription audio – JT-Tools by Johnny"
APP_COMMENT_WIN="Gestionnaire de transcription audio - JT-Tools by Johnny"
APP_CATS="Audio;AudioVideo;Office;"
APP_KEYWORDS="transcription;audio;dictée;pédalier;olympus;"
MAIN_SCRIPT="transcribe_station.py"
ICON_PNG="icon.png"
ICON_ICO="icon.ico"
DIST_LINUX="dist/linux"
DIST_WINDOWS="dist/windows"
VENV_DIR=".venv"

HIDDEN_IMPORTS=(
    "PyQt6.QtMultimedia"
    "PyQt6.QtCore"
    "PyQt6.QtGui"
    "PyQt6.QtWidgets"
    "soundfile"
    "numpy"
    "hid"
    "cffi"
    "_cffi_backend"
)

# ── Couleurs ───────────────────────────────────────────────────────────────────
R='\033[0;31m' G='\033[0;32m' Y='\033[1;33m'
C='\033[0;36m' B='\033[1m'    N='\033[0m'

ok()   { echo -e "${G}[OK]${N}    $*"; }
info() { echo -e "${C}[..]${N}    $*"; }
warn() { echo -e "${Y}[!!]${N}    $*"; }
err()  { echo -e "${R}[XX]${N}    $*" >&2; }
step() { echo -e "\n${B}══ $* ══${N}"; }
die()  { err "$*"; exit 1; }

# ── Détection Python / venv ────────────────────────────────────────────────────
find_python() {
    if [[ -f "$VENV_DIR/bin/python" ]]; then
        echo "$VENV_DIR/bin/python"
    elif command -v python3 &>/dev/null; then
        echo "$(command -v python3)"
    else
        die "python3 introuvable. Installez Python 3.10+."
    fi
}

find_pip() {
    local py; py=$(find_python)
    echo "$py -m pip"
}

# ── Validation PyQt6 dans Wine ────────────────────────────────────────────────
check_wine_pyqt_runtime() {
    local wine_cmd="$1"
    local wine_python="$2"
    local wine_run=("env" "WINEDEBUG=-all,err+all" "$wine_cmd")
    local probe_output
    local rc

    probe_output=$("${wine_run[@]}" "$wine_python" -c $'from pathlib import Path\nimport importlib.metadata as md\nimport PyQt6\nqt_dir = Path(PyQt6.__file__).resolve().parent / "Qt6" / "bin"\nmissing = [name for name in ("icuuc.dll", "icuin.dll", "icudt.dll") if not (qt_dir / name).exists()]\nprint("PYQT6_VERSION=" + md.version("PyQt6"))\ntry:\n    print("PYQT6_QT6_VERSION=" + md.version("PyQt6-Qt6"))\nexcept Exception:\n    print("PYQT6_QT6_VERSION=?")\nprint("QT_BIN=" + str(qt_dir).replace(chr(92), "/"))\nprint("MISSING_DLLS=" + ",".join(missing))\nfrom PyQt6 import QtCore\nprint("QTCORE_OK=1")' 2>&1)
    rc=$?

    while IFS= read -r line; do
        [[ -n "$line" ]] && info "Wine Qt probe : $line"
    done <<< "$probe_output"

    if [[ $rc -ne 0 ]]; then
        local missing_dlls=""
        missing_dlls=$(printf '%s\n' "$probe_output" | sed -n 's/^MISSING_DLLS=//p' | tail -n1)
        err "PyQt6 est installé dans Wine, mais QtCore ne se charge pas."
        [[ -n "$missing_dlls" ]] && err "DLL Qt manquantes dans le wheel Windows : $missing_dlls"
        err "Le binaire Windows généré via Wine serait invalide."
        err "Utilisez dist/windows/build_windows.bat sur Windows natif."
        return 1
    fi
}

# ── Génération des icônes via Python/Pillow ────────────────────────────────────
generate_icons() {
    step "Génération des icônes"
    local py; py=$(find_python)

    if ! $py -c "import PIL" 2>/dev/null; then
        info "Installation de Pillow..."
        $py -m pip install --quiet Pillow
    fi

    info "Création de $ICON_PNG et $ICON_ICO..."
    $py - << 'PYICON'
from PIL import Image, ImageDraw
import sys

def draw_logo(draw, sz):
    draw.rounded_rectangle(
        [0, 0, sz - 1, sz - 1],
        radius=int(sz * 0.18),
        fill=(59, 110, 220, 255),
    )
    bars = [0.25, 0.45, 0.70, 0.90, 0.65, 1.0, 0.55, 0.80, 0.40, 0.20]
    n, mg = len(bars), sz * 0.13
    bw  = (sz - 2 * mg) / (n * 1.7)
    gap = (sz - 2 * mg) / n
    mid = sz / 2
    for i, h in enumerate(bars):
        x  = mg + i * gap + (gap - bw) / 2
        bh = h * sz * 0.36
        draw.rounded_rectangle(
            [x, mid - bh, x + bw, mid + bh],
            radius=bw / 2,
            fill=(255, 255, 255, 215),
        )

sizes = [16, 32, 48, 64, 128, 256]
images = []
for sz in sizes:
    img = Image.new("RGBA", (sz, sz), (0, 0, 0, 0))
    draw_logo(ImageDraw.Draw(img), sz)
    images.append(img)

images[-1].save("icon.png")
images[0].save("icon.ico", format="ICO",
               sizes=[(s, s) for s in sizes],
               append_images=images[1:])
print("OK")
PYICON

    [[ -f "$ICON_PNG" ]] && ok "$ICON_PNG généré" || warn "$ICON_PNG absent (Pillow échoué ?)"
    [[ -f "$ICON_ICO" ]] && ok "$ICON_ICO généré" || warn "$ICON_ICO absent"
}

# ── Build PyInstaller Linux ────────────────────────────────────────────────────
build_linux() {
    step "Build Linux (PyInstaller --onefile)"

    local py; py=$(find_python)

    # Vérifier / installer PyInstaller
    if ! $py -m PyInstaller --version &>/dev/null; then
        info "Installation de PyInstaller..."
        $py -m pip install --quiet pyinstaller
    fi

    generate_icons

    # Construire les arguments hidden-import
    local hi_args=()
    for h in "${HIDDEN_IMPORTS[@]}"; do
        hi_args+=("--hidden-import=$h")
    done

    # Argument icône (optionnel)
    local icon_arg=()
    [[ -f "$ICON_ICO" ]] && icon_arg=("--icon=$ICON_ICO")

    info "Lancement de PyInstaller..."
    $py -m PyInstaller \
        --onefile \
        --clean \
        --noconfirm \
        --name="$APP_NAME" \
        --distpath="$DIST_LINUX" \
        --workpath="build/linux" \
        --specpath="build/linux" \
        --log-level=WARN \
        "${hi_args[@]}" \
        "${icon_arg[@]}" \
        "$MAIN_SCRIPT"

    local binary="$DIST_LINUX/$APP_NAME"
    if [[ -f "$binary" ]]; then
        chmod +x "$binary"
        local size
        size=$(du -m "$binary" | cut -f1)
        ok "Binaire : $binary  (${size} Mo)"

        # Copier l'icône PNG à côté du binaire (chemin absolu dans le .desktop)
        if [[ -f "$ICON_PNG" ]]; then
            cp "$ICON_PNG" "$DIST_LINUX/$APP_NAME.png"
            ok "Icône copiée : $DIST_LINUX/$APP_NAME.png"
        fi
    else
        die "Binaire introuvable dans $DIST_LINUX/"
    fi
}

# ── Installation raccourci GNOME ───────────────────────────────────────────────
install_gnome_shortcut() {
    step "Installation raccourci GNOME"

    local binary
    binary="$(pwd)/$DIST_LINUX/$APP_NAME"
    [[ -f "$binary" ]] || die "Binaire introuvable : $binary  (lancez d'abord --linux)"

    # 1. Icône XDG hicolor (prioritaire) + fallback chemin absolu
    local icon_dir="$HOME/.local/share/icons/hicolor/256x256/apps"
    local icon_ref="$APP_NAME"        # référence symbolique XDG (défaut)
    local icon_sizes=("16x16" "32x32" "48x48" "64x64" "128x128" "256x256")

    mkdir -p "$icon_dir"

    # Chercher l'icône : priorité au dist/linux/ puis au répertoire courant
    local icon_src=""
    for candidate in "$DIST_LINUX/$APP_NAME.png" "$ICON_PNG"; do
        [[ -f "$candidate" ]] && icon_src="$candidate" && break
    done

    if [[ -n "$icon_src" ]]; then
        # Installer dans tous les formats XDG disponibles
        for sz in "${icon_sizes[@]}"; do
            local sz_dir="$HOME/.local/share/icons/hicolor/$sz/apps"
            mkdir -p "$sz_dir"
        done
        cp "$icon_src" "$icon_dir/$APP_NAME.png"
        ok "Icône XDG installée : $icon_dir/$APP_NAME.png"

        # Fallback : chemin absolu si XDG n'est pas disponible
        icon_ref="$icon_dir/$APP_NAME.png"
    else
        warn "Aucune icône trouvée — raccourci sans icône"
        warn "Relancez après --linux pour générer $ICON_PNG"
    fi

    # 2. Fichier .desktop
    local apps_dir="$HOME/.local/share/applications"
    mkdir -p "$apps_dir"
    local desktop="$apps_dir/$APP_NAME.desktop"

    cat > "$desktop" << DESKTOP
[Desktop Entry]
Version=1.0
Type=Application
Name=$APP_NAME
GenericName=Transcription Audio
Comment=$APP_COMMENT
Exec=$binary
Icon=$icon_ref
Terminal=false
Categories=$APP_CATS
StartupNotify=true
StartupWMClass=$APP_NAME
Keywords=$APP_KEYWORDS
DESKTOP

    chmod 755 "$desktop"
    ok ".desktop installé : $desktop"

    # 3. Raccourci bureau (Bureau / Desktop / Escritorio)
    local placed=false
    for bureau_name in "Bureau" "Desktop" "Escritorio"; do
        local bureau_dir="$HOME/$bureau_name"
        if [[ -d "$bureau_dir" ]]; then
            cp "$desktop" "$bureau_dir/$APP_NAME.desktop"
            chmod 755 "$bureau_dir/$APP_NAME.desktop"
            ok "Raccourci bureau : $bureau_dir/$APP_NAME.desktop"
            placed=true
            break
        fi
    done
    $placed || warn "Dossier Bureau/Desktop introuvable — raccourci bureau ignoré"

    # 4. Mise à jour des bases de données
    for cmd_args in \
        "update-desktop-database $apps_dir" \
        "gtk-update-icon-cache -f -t $HOME/.local/share/icons/hicolor" \
        "xdg-desktop-menu forceupdate"
    do
        local cmd; cmd=$(echo "$cmd_args" | cut -d' ' -f1)
        if command -v "$cmd" &>/dev/null; then
            # shellcheck disable=SC2086
            $cmd_args 2>/dev/null && info "Mise à jour : $cmd" || true
        fi
    done

    ok "Raccourci GNOME installé — visible après reconnexion si nécessaire"
}

# ── Désinstallation raccourci GNOME ───────────────────────────────────────────
uninstall_gnome_shortcut() {
    step "Désinstallation raccourci GNOME"
    local removed=false

    local targets=(
        "$HOME/.local/share/applications/$APP_NAME.desktop"
        "$HOME/.local/share/icons/hicolor/256x256/apps/$APP_NAME.png"
        "$HOME/Bureau/$APP_NAME.desktop"
        "$HOME/Desktop/$APP_NAME.desktop"
        "$HOME/Escritorio/$APP_NAME.desktop"
    )

    for t in "${targets[@]}"; do
        if [[ -e "$t" ]]; then
            rm -f "$t"
            ok "Supprimé : $t"
            removed=true
        fi
    done

    $removed || info "Aucun fichier à supprimer"

    if command -v update-desktop-database &>/dev/null; then
        update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
    fi
}

# ── Génération build_windows.bat ──────────────────────────────────────────────
build_windows() {
    step "Génération du script Windows"

    mkdir -p "$DIST_WINDOWS"

    # Construire la liste des --hidden-import pour le .bat
    local hi_bat=""
    for h in "${HIDDEN_IMPORTS[@]}"; do
        hi_bat+="    --hidden-import $h ^\n"
    done

    # Construire les arguments hidden-import pour le .bat
    local hi_bat_args=""
    for h in "${HIDDEN_IMPORTS[@]}"; do
        hi_bat_args+="    --hidden-import $h ^\\"$'\n'
    done

    cat > "$DIST_WINDOWS/build_windows.bat" << WINBAT
@echo off
chcp 65001 > nul
setlocal EnableDelayedExpansion
REM ═══════════════════════════════════════════════════════════════
REM  build_windows.bat – $APP_NAME v$APP_VERSION
REM  JT-Tools by Johnny – H3Campus
REM  Compatible : Windows natif ET Wine (Linux)
REM ═══════════════════════════════════════════════════════════════
echo.
echo  *** Build $APP_NAME v$APP_VERSION ***
echo.

REM ── Localiser le dossier projet ───────────────────────────────────────
set "SCRIPT_DIR=%~dp0"
for %%I in ("%CD%") do set "PROJECT_ROOT=%%~fI"
if exist "%PROJECT_ROOT%\$MAIN_SCRIPT" goto :ROOT_FOUND
for %%I in ("%SCRIPT_DIR%\..\..") do set "PROJECT_ROOT=%%~fI"
if exist "%PROJECT_ROOT%\$MAIN_SCRIPT" goto :ROOT_FOUND
for %%I in ("%SCRIPT_DIR%") do set "PROJECT_ROOT=%%~fI"
if exist "%PROJECT_ROOT%\$MAIN_SCRIPT" goto :ROOT_FOUND
echo [XX] $MAIN_SCRIPT introuvable.
echo [XX] Placez build_windows.bat dans dist\windows\ du projet,
echo [XX] ou lancez-le depuis la racine contenant $MAIN_SCRIPT.
pause & exit /b 1

:ROOT_FOUND
cd /d "%PROJECT_ROOT%"
echo [OK] Dossier projet : %PROJECT_ROOT%
echo.

REM ── Localiser Python (cherche dans les emplacements standard) ─────────
set PYTHON_EXE=

REM Essayer d'abord "python" dans le PATH
python --version >nul 2>&1
if not errorlevel 1 ( set PYTHON_EXE=python & goto :PYTHON_FOUND )

REM Chercher dans les emplacements fixes courants
for %%P in (
    "C:\Python312\python.exe"
    "C:\Python311\python.exe"
    "C:\Python310\python.exe"
    "C:\Python39\python.exe"
    "%LOCALAPPDATA%\Programs\Python\Python312\python.exe"
    "%LOCALAPPDATA%\Programs\Python\Python311\python.exe"
    "%LOCALAPPDATA%\Programs\Python\Python310\python.exe"
    "%APPDATA%\..\Local\Programs\Python\Python312\python.exe"
) do (
    if exist %%P ( set PYTHON_EXE=%%P & goto :PYTHON_FOUND )
)

REM Utiliser le launcher py si disponible
py -3.12 --version >nul 2>&1 && set PYTHON_EXE=py -3.12 & goto :PYTHON_FOUND
py -3.11 --version >nul 2>&1 && set PYTHON_EXE=py -3.11 & goto :PYTHON_FOUND
py --version >nul 2>&1 && set PYTHON_EXE=py & goto :PYTHON_FOUND

echo [XX] Python introuvable. Installez Python 3.12 :
echo      https://www.python.org/ftp/python/3.12.10/python-3.12.10-amd64.exe
pause & exit /b 1

:PYTHON_FOUND
for /f "tokens=2" %%v in ('%PYTHON_EXE% --version 2^>^&1') do set PY_FOUND=%%v
echo [OK] Python trouve : %PYTHON_EXE% (%PY_FOUND%)
echo.

REM ── Ajouter Scripts/ au PATH pour que pip/pyinstaller soit accessible ─
for /f "delims=" %%d in ('%PYTHON_EXE% -c "import sysconfig; print(sysconfig.get_path(chr(115)+chr(99)+chr(114)+chr(105)+chr(112)+chr(116)+chr(115)))"') do set PY_SCRIPTS=%%d
if defined PY_SCRIPTS ( set PATH=%PY_SCRIPTS%;%PATH% )

REM ── [1/4] Installation des dependances ───────────────────────────────
echo [1/4] Installation des dependances Python...
%PYTHON_EXE% -m pip install --upgrade pip setuptools wheel --quiet
%PYTHON_EXE% -m pip install pyinstaller PyQt6 PyQt6-Qt6 numpy soundfile hid Pillow ^
    --prefer-binary --quiet ^
    --trusted-host pypi.org ^
    --trusted-host pypi.python.org ^
    --trusted-host files.pythonhosted.org
if errorlevel 1 (
    echo [XX] Echec pip install. Nouvelle tentative sans --quiet...
    %PYTHON_EXE% -m pip install pyinstaller PyQt6 PyQt6-Qt6 numpy soundfile hid Pillow ^
        --prefer-binary ^
        --trusted-host pypi.org ^
        --trusted-host pypi.python.org ^
        --trusted-host files.pythonhosted.org
    if errorlevel 1 ( echo [XX] ERREUR installation paquets & pause & exit /b 1 )
)
echo [OK] Dependances installees.
%PYTHON_EXE% -c "from PyQt6 import QtCore"
if errorlevel 1 (
    echo [XX] PyQt6 est installe mais QtCore ne se charge pas.
    echo [XX] Verifiez PyQt6 / PyQt6-Qt6 ou essayez une autre version.
    pause & exit /b 1
)
echo.

REM ── [2/4] Generation des icones (via fichier temp) ───────────────────
echo [2/4] Generation des icones...

REM Ecrire le script Python dans un fichier temp (evite les problemes de guillemets cmd)
set ICON_PY=%TEMP%\build_icon_%RANDOM%.py
(
echo from PIL import Image, ImageDraw
echo def logo(d, sz^):
echo     d.rounded_rectangle([0,0,sz-1,sz-1], radius=int(sz*.18^), fill=(59,110,220,255^)^)
echo     bars=[.25,.45,.7,.9,.65,1.,.55,.8,.4,.2]
echo     n,mg=len(bars^),sz*.13; bw=(sz-2*mg^)/(n*1.7^); gap=(sz-2*mg^)/n; mid=sz/2
echo     for i,h in enumerate(bars^):
echo         x=mg+i*gap+(gap-bw^)/2; bh=h*sz*.36
echo         d.rounded_rectangle([x,mid-bh,x+bw,mid+bh],radius=bw/2,fill=(255,255,255,215^)^)
echo sizes=[16,32,48,64,128,256]; imgs=[]
echo for sz in sizes:
echo     img=Image.new('RGBA',(sz,sz^),(0,0,0,0^)^); logo(ImageDraw.Draw(img^),sz^); imgs.append(img^)
echo imgs[-1].save('icon.png'^)
echo imgs[0].save('icon.ico',format='ICO',sizes=[(s,s^) for s in sizes],append_images=imgs[1:]^)
echo print('[OK] Icones generees'^)
) > "%ICON_PY%"

%PYTHON_EXE% "%ICON_PY%"
del "%ICON_PY%" 2>nul
if not exist icon.ico ( echo [!!] Icone ignoree (Pillow absent ?^) ) else ( echo [OK] icon.ico et icon.png. )
echo.

REM ── [3/4] Compilation PyInstaller ────────────────────────────────────
echo [3/4] Compilation PyInstaller...
%PYTHON_EXE% -m PyInstaller ^
    --onedir --windowed --clean --noconfirm ^
    --name $APP_NAME ^
    --distpath "%PROJECT_ROOT%\dist\windows" ^
    --workpath "%PROJECT_ROOT%\build\windows" ^
    --specpath "%PROJECT_ROOT%\build\windows" ^
    --hidden-import PyQt6.QtMultimedia ^
    --hidden-import PyQt6.QtCore ^
    --hidden-import PyQt6.QtGui ^
    --hidden-import PyQt6.QtWidgets ^
    --hidden-import soundfile ^
    --hidden-import numpy ^
    --hidden-import hid ^
    --hidden-import cffi ^
    --hidden-import _cffi_backend ^
    --icon "%PROJECT_ROOT%\icon.ico" ^
    "%PROJECT_ROOT%\$MAIN_SCRIPT"
if errorlevel 1 ( echo [XX] ERREUR PyInstaller & pause & exit /b 1 )
echo [OK] Binaire : %PROJECT_ROOT%\dist\windows\$APP_NAME\$APP_NAME.exe
echo.

REM ── [4/4] Raccourcis Bureau + Menu Demarrer ───────────────────────────
echo [4/4] Installation des raccourcis...
if exist "%PROJECT_ROOT%\dist\windows\install_shortcut.ps1" (
    powershell -NoProfile -ExecutionPolicy Bypass ^
      -File "%PROJECT_ROOT%\dist\windows\install_shortcut.ps1" ^
      -ExePath "%PROJECT_ROOT%\dist\windows\$APP_NAME\$APP_NAME.exe"
) else (
    echo [!!] Script PowerShell introuvable : %PROJECT_ROOT%\dist\windows\install_shortcut.ps1
)

echo.
echo  *** Build termine ! ***
echo  Binaire    : %PROJECT_ROOT%\dist\windows\$APP_NAME\$APP_NAME.exe
echo  Raccourcis : Bureau + Menu Demarrer
echo.
pause
WINBAT

    # Script PowerShell standalone pour install raccourci seulement
    cat > "$DIST_WINDOWS/install_shortcut.ps1" << PSSCRIPT
# install_shortcut.ps1 - Install shortcuts for $APP_NAME
# Usage : powershell -ExecutionPolicy Bypass -File install_shortcut.ps1
param([string]\$ExePath = "")

if (-not \$ExePath) {
    \$here = Split-Path \$MyInvocation.MyCommand.Path
    \$ExePath = Join-Path \$here "$APP_NAME\$APP_NAME.exe"
    if (-not (Test-Path \$ExePath)) {
        \$ExePath = Join-Path \$here "$APP_NAME.exe"
    }
}

if (-not (Test-Path \$ExePath)) {
    Write-Error "Executable introuvable : \$ExePath"
    exit 1
}

\$exe  = Resolve-Path \$ExePath
\$desc = "$APP_COMMENT_WIN"
\$dirs = @(
    [Environment]::GetFolderPath("Desktop"),
    "\$env:APPDATA\Microsoft\Windows\Start Menu\Programs"
)

foreach (\$dir in \$dirs) {
    \$lnk = Join-Path \$dir "$APP_NAME.lnk"
    \$wsh = New-Object -ComObject WScript.Shell
    \$sc  = \$wsh.CreateShortcut(\$lnk)
    \$sc.TargetPath       = \$exe
    \$sc.IconLocation     = "\$exe,0"
    \$sc.Description      = \$desc
    \$sc.WorkingDirectory = Split-Path \$exe
    \$sc.Save()
    Write-Host "[OK] Raccourci : \$lnk"
}

Write-Host ""
Write-Host "[OK] Installation terminee."
PSSCRIPT

    ok "Script Windows : $DIST_WINDOWS/build_windows.bat"
    ok "Script PowerShell : $DIST_WINDOWS/install_shortcut.ps1"
    echo ""
    warn "Pour Windows natif : copiez dist/windows/ et double-cliquez build_windows.bat"
    echo ""

    # ── Compilation via Wine (appels directs, pas via cmd.exe) ───────────────
    local wine_cmd
    wine_cmd=$(command -v wine64 || command -v wine || true)
    [[ -z "$wine_cmd" ]] && return

    step "Compilation Windows via Wine"
    info "Wine : $wine_cmd"

    # Chercher python.exe dans le préfixe Wine
    local wine_prefix="${WINEPREFIX:-$HOME/.wine}"
    local wine_python=""
    for pyver in Python312 Python311 Python310 Python39; do
        local candidate="$wine_prefix/drive_c/$pyver/python.exe"
        if [[ -f "$candidate" ]]; then
            wine_python="$candidate"
            break
        fi
    done
    # Chercher aussi dans Program Files
    if [[ -z "$wine_python" ]]; then
        for base in "$wine_prefix/drive_c/users/$USER/AppData/Local/Programs"                     "$wine_prefix/drive_c/Program Files"                     "$wine_prefix/drive_c/Program Files (x86)"; do
            for pyver in Python312 Python311 Python310; do
                local candidate="$base/Python/$pyver/python.exe"
                [[ -f "$candidate" ]] && wine_python="$candidate" && break 2
            done
        done
    fi

    if [[ -z "$wine_python" ]]; then
        warn "Python Windows introuvable dans Wine ($wine_prefix)."
        warn "Installez-le avec :"
        info "  wget https://www.python.org/ftp/python/3.12.10/python-3.12.10-amd64.exe"
        info "  wine python-3.12.10-amd64.exe /quiet InstallAllUsers=0 TargetDir=C:\\Python312"
        info "Puis relancez : ./build.sh --windows"
        return
    fi

    ok "Python Wine : $wine_python"
    # Chemin Windows pour Wine (Z: = racine Linux sur Wine standard)
    local wine_py_win
    wine_py_win=$(winepath -w "$wine_python" 2>/dev/null || echo "$wine_python")

    # Générer les icônes côté Linux avant la compilation
    generate_icons

    # ── Avertissement Wine + numpy ───────────────────────────────────────────────
    # ucrtbase.dll.crealf n'est pas implémenté dans Wine → numpy crashe PyInstaller.
    # PyInstaller découvre les hooks via les entry_points de TOUS les paquets installés.
    # Si numpy est présent dans le Python Wine, son hook crashe Wine même avec --exclude-module.
    # Solution : désinstaller numpy/soundfile AVANT PyInstaller, réinstaller si nécessaire.
    warn "Build Wine : numpy/soundfile seront temporairement désinstallés du Python Wine"
    warn "             (ucrtbase.dll.crealf non implémenté → PyInstaller crasherait)."
    warn "             La waveform sera absente du .exe Wine."
    warn "             Pour un .exe complet → build_windows.bat sur Windows natif."
    echo ""

    # WINEDEBUG via variable d'environnement pour Wine lui-même (pas export bash)
    # Utiliser WINEDEBUG dans la commande wine directement
    local wine_run=("env" "WINEDEBUG=-all,err+all" "$wine_cmd")

    local pip_trust=(
        --trusted-host pypi.org
        --trusted-host pypi.python.org
        --trusted-host files.pythonhosted.org
    )

    info "Mise à jour de pip dans Wine..."
    "${wine_run[@]}" "$wine_python" -m pip install --upgrade pip setuptools wheel         --quiet "${pip_trust[@]}" 2>/dev/null || true

    # ── Désinstaller numpy/soundfile/scipy du Python Wine ────────────────────────
    # (ils peuvent rester d'une installation précédente)
    info "Désinstallation de numpy/soundfile/scipy du Python Wine (anti-crash ucrtbase)..."
    "${wine_run[@]}" "$wine_python" -m pip uninstall -y         numpy soundfile scipy PyInstaller-hooks-contrib 2>/dev/null || true

    # ── Installer les dépendances sans numpy/soundfile ────────────────────────────
    info "Installation PyInstaller + PyQt6 (sans numpy/soundfile)..."
    "${wine_run[@]}" "$wine_python" -m pip install         pyinstaller PyQt6 PyQt6-Qt6 hid Pillow         --prefer-binary --quiet "${pip_trust[@]}"
    if [[ $? -ne 0 ]]; then
        err "Échec pip install Wine."
        return
    fi
    ok "Dépendances installées (PyQt6 + PyInstaller, sans numpy)."

    check_wine_pyqt_runtime "$wine_cmd" "$wine_python" || return 1

    # ── Vérifier que numpy est bien absent ───────────────────────────────────────
    if "${wine_run[@]}" "$wine_python" -c "import numpy" 2>/dev/null; then
        err "numpy est encore présent dans le Python Wine malgré la désinstallation."
        err "Désinstallez-le manuellement : wine $wine_python -m pip uninstall -y numpy"
        return
    fi
    ok "numpy absent du Python Wine — PyInstaller peut s'exécuter."

    info "Lancement de PyInstaller (Windows via Wine)..."

    # Hidden imports : exclure ce qui crashe Wine
    local hi_args_wine=()
    for h in "${HIDDEN_IMPORTS[@]}"; do
        case "$h" in
            numpy|soundfile|scipy|cffi|_cffi_backend) ;;
            *) hi_args_wine+=(--hidden-import "$h") ;;
        esac
    done

    local icon_arg_wine=()
    [[ -f "$ICON_ICO" ]] &&         icon_arg_wine=(--icon "$(winepath -w "$(pwd)/$ICON_ICO" 2>/dev/null || echo "$ICON_ICO")")

    local src_win;    src_win=$(winepath -w   "$(pwd)/$MAIN_SCRIPT"    2>/dev/null || echo "$MAIN_SCRIPT")
    local dist_win;   dist_win=$(winepath -w  "$(pwd)/$DIST_WINDOWS"   2>/dev/null || echo "$DIST_WINDOWS")
    local build_win;  build_win=$(winepath -w "$(pwd)/build/windows"   2>/dev/null || echo "build/windows")

    "${wine_run[@]}" "$wine_python" -m PyInstaller         --onefile --windowed --clean --noconfirm         --name="$APP_NAME"         --distpath="$dist_win"         --workpath="$build_win"         --specpath="$build_win"         --log-level=WARN         --exclude-module numpy         --exclude-module soundfile         --exclude-module scipy         --exclude-module _multiarray_umath         "${hi_args_wine[@]}"         "${icon_arg_wine[@]}"         "$src_win" 2>&1 | grep -v "^0[0-9a-f]*:fixme:\|^0[0-9a-f]*:err:\|WineDbg\|Register dump\|Stack dump\|Backtrace\|Modules:\|Threads:\|System info"
    local rc=${PIPESTATUS[0]}

    local binary="$DIST_WINDOWS/$APP_NAME.exe"
    if [[ -f "$binary" && $rc -eq 0 ]]; then
        local size; size=$(du -m "$binary" | cut -f1)
        ok "Binaire Windows : $binary  (${size} Mo)"
        warn "Ce binaire N'INCLUT PAS la waveform (numpy exclu pour compatibilité Wine)."
        warn "Pour un .exe complet avec waveform :"
        warn "  Copiez build_windows.bat sur une machine Windows et exécutez-le."
    else
        err "PyInstaller échoué (code $rc)."
        err "Solution recommandée : utilisez build_windows.bat sur Windows natif."
    fi
}

# ── Nettoyage ──────────────────────────────────────────────────────────────────
clean() {
    step "Nettoyage"
    local removed=false

    for target in build dist "$ICON_PNG" "$ICON_ICO" *.spec; do
        if [[ -e "$target" ]]; then
            rm -rf "$target"
            ok "Supprimé : $target"
            removed=true
        fi
    done

    $removed || info "Rien à nettoyer"
}

# ── Aide ───────────────────────────────────────────────────────────────────────
usage() {
    sed -n '2,15p' "$0" | sed 's/^# \{0,1\}//'
    exit 0
}

# ── Résumé final ───────────────────────────────────────────────────────────────
summary() {
    echo ""
    echo -e "${B}${G}╔══════════════════════════════════════════╗${N}"
    echo -e "${B}${G}║   $APP_NAME v$APP_VERSION – Build OK   ║${N}"
    echo -e "${B}${G}╚══════════════════════════════════════════╝${N}"
    echo ""
    [[ -f "$DIST_LINUX/$APP_NAME" ]] && \
        echo -e "  Linux  : ${C}$DIST_LINUX/$APP_NAME${N}"
    [[ -f "$DIST_WINDOWS/build_windows.bat" ]] && \
        echo -e "  Windows: ${C}$DIST_WINDOWS/build_windows.bat${N}"
    echo ""
}

# ── Point d'entrée ─────────────────────────────────────────────────────────────
main() {
    # Aller dans le répertoire du script
    cd "$(dirname "$(realpath "$0")")"

    # Vérifications de base
    [[ $EUID -eq 0 ]] && die "Ne pas exécuter en root."
    [[ -f "$MAIN_SCRIPT" ]] || die "$MAIN_SCRIPT introuvable dans $(pwd)"

    local do_linux=false
    local do_windows=false
    local do_install=true
    local do_install_only=false
    local do_uninstall=false
    local do_clean=false

    # Défaut : si aucun argument, build linux
    [[ $# -eq 0 ]] && do_linux=true && do_install=true

    while [[ $# -gt 0 ]]; do
        case "$1" in
            --linux)         do_linux=true ;;
            --windows)       do_windows=true ;;
            --both)          do_linux=true; do_windows=true ;;
            --no-install)    do_install=false ;;
            --install-only)  do_install_only=true ;;
            --uninstall)     do_uninstall=true ;;
            --clean)         do_clean=true ;;
            --help|-h)       usage ;;
            *) die "Option inconnue : $1  (--help pour l'aide)" ;;
        esac
        shift
    done

    # ── Actions exclusives ──────────────────────────────────────────────────
    if $do_clean;        then clean;                   exit 0; fi
    if $do_uninstall;    then uninstall_gnome_shortcut; exit 0; fi
    if $do_install_only; then
        generate_icons
        install_gnome_shortcut
        exit 0
    fi

    # ── Affichage de l'en-tête ─────────────────────────────────────────────
    echo -e "\n${B}╔══════════════════════════════════════════════╗${N}"
    echo -e "${B}║     $APP_NAME – Build v$APP_VERSION           ║${N}"
    echo -e "${B}║     JT-Tools by Johnny · H3Campus            ║${N}"
    echo -e "${B}╚══════════════════════════════════════════════╝${N}"

    # ── Build Linux ─────────────────────────────────────────────────────────
    if $do_linux; then
        build_linux
        $do_install && install_gnome_shortcut
    fi

    # ── Build Windows ───────────────────────────────────────────────────────
    if $do_windows; then
        build_windows
    fi

    summary
}

main "$@"
