#!/usr/bin/env bash
# ffmpeg REDISTRIBUABLE pour l'app pcr Windows x64 — GPL v3, SANS `--enable-nonfree` — CROSS-COMPILÉ DEPUIS LE MAC
# (mingw-w64, comme le relais apps/wds-ndi-send). Décision Jérôme du 02/10 (docs/RD/VIRTUAL_WEBCAM.md §13,
# BUGS_ENHANCEMENTS [licences/packaging]) : remplacer le binaire gyan.dev (via eugeneware/ffmpeg-static b6.0,
# GPL mais sources correspondantes jamais publiées) par un build maison dont on publie les sources.
#
# Même recette que build-ffmpeg-mac.sh, avec ce que le pcr Windows utilise (apps/pcr-server : dshow pour les sources
# directes, h264_amf (PC AMD de régie) + libx264 en repli, libopus/aac, libsrt (relais cloud), rtsp/rtmp/mpegts/mp4,
# scale/fps/aresample ; ffprobe pour media-upload) + h264_nvenc/hevc_nvenc (en-têtes NVIDIA, MIT) :
#   openssl (Apache-2.0) → srt (MPL-2.0) ; x264 (GPL-2.0+) ; opus (BSD-3) ; nv-codec-headers (MIT) ; AMF headers (MIT) ;
#   ffmpeg (GPL-3.0+ via --enable-version3 — requis aussi pour lier OpenSSL 3 sous GPL)
# Binaire 100 % statique (-static -static-libgcc -static-libstdc++) : aucune DLL hors système.
#
# Sortie : resources/pack/win-x64/ffmpeg/{ffmpeg.exe,ffprobe.exe} + THIRD-PARTY-LICENSES/ (textes + SOURCES.txt).
# Le lot de sources correspondantes (archives + ce script) est complété dans resources/pack/.cache/ffmpeg-sources-<v>/
# (publication : scripts/package/publish-ffmpeg-sources.sh).
#
#   scripts/package/build-ffmpeg-win.sh            # build complet (~15 min sur M4 Pro)
#   scripts/package/build-ffmpeg-win.sh --check    # vérifie le binaire présent SANS l'exécuter (PE statique, config, symboles)
#
# Prérequis : brew install mingw-w64 nasm cmake pkg-config (perl du système pour openssl).
# ⚠ Un binaire Windows ne s'exécute pas ici : le --check est statique ; le smoke fonctionnel se fait sur la VM
#   wds-build-win (docs/APPS_RELEASE_WORKFLOW.md) — et le banc du relais NDI sur le PC de régie.
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
PACK="$ROOT/resources/pack"
OUT="$PACK/win-x64/ffmpeg"
WORK="$PACK/.cache/ffmpeg-build"
SRC="$WORK/src"              # archives + clones partagés avec les builds mac/linux
BUILD="$WORK/win"            # arbres de build PROPRES à cette cible (jamais ceux du Mac : in-tree)
PREFIX="$BUILD/prefix"
HOST=x86_64-w64-mingw32
JOBS="$(sysctl -n hw.ncpu)"

FFMPEG_VERSION="${FFMPEG_VERSION:-8.1.1}"
OPUS_VERSION="${OPUS_VERSION:-1.6.1}"
SRT_VERSION="${SRT_VERSION:-1.5.7}"
OPENSSL_VERSION="${OPENSSL_VERSION:-3.6.5}"
X264_REF="${X264_REF:-stable}"
NVHDR_REF="${NVHDR_REF:-n13.0.19.1}"   # FFmpeg/nv-codec-headers — ⚠ n13.1.x casse ffmpeg 8.1.1 (countingType → countingTypeLSB), rester en 13.0.x
AMF_REF="${AMF_REF:-v1.5.3}"           # GPUOpen AMF, en-têtes seuls (ffmpeg 8.1.1 exige ≥ 1.4.36)

SRC_FFMPEG="https://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.xz"
SRC_OPUS="https://ftp.osuosl.org/pub/xiph/releases/opus/opus-$OPUS_VERSION.tar.gz"
SRC_SRT="https://github.com/Haivision/srt/archive/refs/tags/v$SRT_VERSION.tar.gz"
SRC_OPENSSL="https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VERSION/openssl-$OPENSSL_VERSION.tar.gz"
SRC_X264="https://code.videolan.org/videolan/x264.git"
SRC_NVHDR="https://github.com/FFmpeg/nv-codec-headers.git"
SRC_AMF="https://github.com/GPUOpen-LibrariesAndSDKs/AMF.git"

step() { echo "=== $(date +%H:%M:%S) $*"; }

# DLL système autorisées pour un binaire « statique » Windows (tout le reste = dépendance oubliée).
SYSTEM_DLLS='^(KERNEL32|USER32|GDI32|ADVAPI32|SHELL32|OLE32|OLEAUT32|WS2_32|CRYPT32|BCRYPT|SHLWAPI|PSAPI|IMM32|VERSION|SECUR32|AVICAP32|VFW32|SETUPAPI|WINMM|MFPLAT|MF|MFUUID|STRMIIDS|DNSAPI|IPHLPAPI|NCRYPT|MSVCRT|API-MS-WIN-[A-Z0-9-]+|UCRTBASE|D3D11|DXGI|COMDLG32|UUID)\.DLL$'

check_binary() {
  local bin="$OUT/ffmpeg.exe" missing=0
  [ -f "$bin" ] || { echo "✗ $bin absent"; return 1; }
  [ -f "$OUT/ffprobe.exe" ] || { echo "✗ ffprobe.exe absent (media-upload le dérive de FFMPEG_BIN)"; missing=1; }
  local kind; kind="$(file -b "$bin")"
  grep -q "PE32+ executable.*x86-64" <<<"$kind" || { echo "✗ pas un PE32+ x86-64 : $kind"; return 1; }
  # ⚠ pipefail + `grep -q`/`head` = SIGPIPE sur `strings` → on capture tout d'abord (vécu 02/10 sur le Mac).
  local all conf; all="$(strings "$bin")"
  conf="$(grep -- "--enable-gpl" <<<"$all" || true)"; conf="${conf%%$'\n'*}"
  [ -n "$conf" ] || { echo "✗ ligne de configure introuvable dans le binaire"; return 1; }
  grep -q -- "--enable-nonfree" <<<"$conf" && { echo "✗ binaire NONFREE"; return 1; }
  grep -q -- "--enable-version3" <<<"$conf" || { echo "✗ pas --enable-version3 (GPL v3 requis avec OpenSSL)"; missing=1; }
  echo "configure : ${conf:0:160}…"
  for flag in --enable-libx264 --enable-libopus --enable-libsrt --enable-openssl --enable-amf --enable-nvenc --target-os=mingw32; do
    grep -q -- "$flag" <<<"$conf" || { echo "✗ configure sans $flag"; missing=1; }
  done
  # Symboles/noms attendus dans le binaire (sans l'exécuter) : encodeurs, périphérique dshow, protocole srt.
  for sym in h264_amf h264_nvenc hevc_nvenc libx264 libopus dshow libsrt; do
    grep -qx "$sym" <<<"$all" || grep -q "$sym" <<<"$all" || { echo "✗ symbole absent : $sym"; missing=1; }
  done
  # Dépendances DLL : système seulement.
  local dlls bad; dlls="$($HOST-objdump -p "$bin" 2>/dev/null | grep "DLL Name:" | sed 's/.*DLL Name: //' | tr 'a-z' 'A-Z' | sort -u || true)"
  bad="$(grep -vE "$SYSTEM_DLLS" <<<"$dlls" || true)"
  if [ -n "$bad" ]; then echo "✗ DLL hors système : $(tr '\n' ' ' <<<"$bad")"; missing=1; else echo "DLL : $(tr '\n' ' ' <<<"$dlls")"; fi
  [ -f "$OUT/THIRD-PARTY-LICENSES/SOURCES.txt" ] || { echo "✗ THIRD-PARTY-LICENSES/SOURCES.txt absent"; missing=1; }
  [ "$missing" = 0 ] && echo "✓ ffmpeg $FFMPEG_VERSION win-x64 redistribuable (GPL v3, sans nonfree, statique) — $(du -h "$bin" | cut -f1)"
  return $missing
}

if [ "${1:-}" = "--check" ]; then check_binary; exit $?; fi

for t in $HOST-gcc $HOST-g++ $HOST-windres nasm cmake pkg-config curl tar perl git file; do
  command -v "$t" >/dev/null || { echo "outil manquant : $t (brew install mingw-w64 nasm cmake pkg-config)"; exit 64; }
done
mkdir -p "$SRC" "$BUILD/src" "$PREFIX" "$OUT"
# Isolement pkg-config : SEULEMENT notre préfixe croisé (jamais les .pc Homebrew du Mac).
export PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig"
unset PKG_CONFIG_PATH

fetch() { [ -f "$2" ] && return 0; echo "  ↓ $1"; curl -fsSL --retry 3 -o "$2.part" "$1" && mv "$2.part" "$2"; }
unpack_fresh() { # unpack_fresh <archive> <dossier> — arbre de build propre pour la cible
  [ -d "$BUILD/src/$2" ] && return 0
  tar xf "$1" -C "$BUILD/src"
}

step "sources (cache partagé $SRC)"
fetch "$SRC_OPENSSL" "$SRC/openssl-$OPENSSL_VERSION.tar.gz"
fetch "$SRC_SRT" "$SRC/srt-$SRT_VERSION.tar.gz"
fetch "$SRC_OPUS" "$SRC/opus-$OPUS_VERSION.tar.gz"
fetch "$SRC_FFMPEG" "$SRC/ffmpeg-$FFMPEG_VERSION.tar.xz"
[ -d "$SRC/x264" ] || git clone -q --branch "$X264_REF" --depth 1 "$SRC_X264" "$SRC/x264"
[ -d "$SRC/nv-codec-headers" ] || git clone -q --branch "$NVHDR_REF" --depth 1 "$SRC_NVHDR" "$SRC/nv-codec-headers"
if [ ! -d "$SRC/AMF" ]; then
  git clone -q --filter=blob:none --sparse --depth 1 --branch "$AMF_REF" "$SRC_AMF" "$SRC/AMF"
  (cd "$SRC/AMF" && git sparse-checkout set amf/public/include >/dev/null)
fi
X264_COMMIT="$(git -C "$SRC/x264" rev-parse HEAD)"
unpack_fresh "$SRC/openssl-$OPENSSL_VERSION.tar.gz" "openssl-$OPENSSL_VERSION"
unpack_fresh "$SRC/srt-$SRT_VERSION.tar.gz" "srt-$SRT_VERSION"
unpack_fresh "$SRC/opus-$OPUS_VERSION.tar.gz" "opus-$OPUS_VERSION"
unpack_fresh "$SRC/ffmpeg-$FFMPEG_VERSION.tar.xz" "ffmpeg-$FFMPEG_VERSION"
[ -d "$BUILD/src/x264" ] || (mkdir -p "$BUILD/src/x264" && git -C "$SRC/x264" archive HEAD | tar x -C "$BUILD/src/x264")

if [ ! -f "$PREFIX/lib/libssl.a" ]; then
  step "openssl $OPENSSL_VERSION (mingw64, statique)"
  (cd "$BUILD/src/openssl-$OPENSSL_VERSION" \
    && ./Configure mingw64 no-shared no-tests no-docs --cross-compile-prefix=$HOST- --prefix="$PREFIX" --libdir=lib > "$BUILD/openssl.log" 2>&1 \
    && make -j"$JOBS" >> "$BUILD/openssl.log" 2>&1 && make install_sw >> "$BUILD/openssl.log" 2>&1) || { tail -20 "$BUILD/openssl.log"; exit 1; }
fi
if [ ! -f "$PREFIX/lib/libsrt.a" ]; then
  step "srt $SRT_VERSION (cmake croisé, openssl, statique)"
  (cd "$BUILD/src/srt-$SRT_VERSION" && rm -rf build && mkdir build && cd build \
    && cmake .. -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_PROCESSOR=AMD64 \
         -DCMAKE_C_COMPILER=$HOST-gcc -DCMAKE_CXX_COMPILER=$HOST-g++ -DCMAKE_RC_COMPILER=$HOST-windres \
         -DCMAKE_FIND_ROOT_PATH="$PREFIX" -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \
         -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
         -DCMAKE_INSTALL_PREFIX="$PREFIX" -DCMAKE_BUILD_TYPE=Release \
         -DENABLE_SHARED=OFF -DENABLE_STATIC=ON -DENABLE_APPS=OFF -DENABLE_ENCRYPTION=ON -DENABLE_STDCXX_SYNC=ON \
         -DUSE_ENCLIB=openssl -DOPENSSL_ROOT_DIR="$PREFIX" -DOPENSSL_USE_STATIC_LIBS=ON -DUSE_OPENSSL_PC=OFF \
         -DOPENSSL_INCLUDE_DIR="$PREFIX/include" -DOPENSSL_SSL_LIBRARY="$PREFIX/lib/libssl.a" -DOPENSSL_CRYPTO_LIBRARY="$PREFIX/lib/libcrypto.a" \
         > "$BUILD/srt.log" 2>&1 \
    && make -j"$JOBS" >> "$BUILD/srt.log" 2>&1 && make install >> "$BUILD/srt.log" 2>&1) || { tail -30 "$BUILD/srt.log"; exit 1; }
  # ⚠ Piège payé le 02/10 : le srt.pc généré par cmake recopie les libs IMPLICITES du toolchain (-lmingw32 -lgcc_s
  # -lgcc -lmingwex -lkernel32 -lpthread …) dans Libs.private ; sous `-static`, `-lgcc_s` (import de libgcc_s_seh-1.dll)
  # cohabite avec libgcc_eh.a → « multiple definition of _Unwind_Resume ». On ne garde que les vraies dépendances.
  perl -pi -e 's/ -l(mingw32|gcc_s|gcc|mingwex|kernel32|pthread|advapi32|shell32|user32|c)(?=\s|$)//g' "$PREFIX/lib/pkgconfig/srt.pc"
fi
if [ ! -f "$PREFIX/lib/libopus.a" ]; then
  step "opus $OPUS_VERSION (statique)"
  (cd "$BUILD/src/opus-$OPUS_VERSION" \
    && ./configure --host=$HOST --prefix="$PREFIX" --disable-shared --enable-static --disable-doc --disable-extra-programs > "$BUILD/opus.log" 2>&1 \
    && make -j"$JOBS" >> "$BUILD/opus.log" 2>&1 && make install >> "$BUILD/opus.log" 2>&1) || { tail -20 "$BUILD/opus.log"; exit 1; }
fi
if [ ! -f "$PREFIX/lib/libx264.a" ]; then
  step "x264 $X264_COMMIT (statique)"
  (cd "$BUILD/src/x264" \
    && ./configure --host=$HOST --cross-prefix=$HOST- --prefix="$PREFIX" --enable-static --disable-cli --enable-pic --disable-opencl > "$BUILD/x264.log" 2>&1 \
    && make -j"$JOBS" >> "$BUILD/x264.log" 2>&1 && make install >> "$BUILD/x264.log" 2>&1) || { tail -20 "$BUILD/x264.log"; exit 1; }
fi
if [ ! -f "$PREFIX/lib/pkgconfig/ffnvcodec.pc" ]; then
  step "nv-codec-headers $NVHDR_REF (en-têtes NVENC/NVDEC)"
  (cd "$SRC/nv-codec-headers" && make install PREFIX="$PREFIX" > "$BUILD/nvhdr.log" 2>&1) || { tail "$BUILD/nvhdr.log"; exit 1; }
fi
if [ ! -f "$PREFIX/include/AMF/core/Version.h" ]; then
  step "AMF $AMF_REF (en-têtes AMD)"
  mkdir -p "$PREFIX/include/AMF" && cp -R "$SRC/AMF/amf/public/include/"* "$PREFIX/include/AMF/"
fi

step "ffmpeg $FFMPEG_VERSION (mingw32 x86_64, statique)"
FFMPEG_CONFIGURE=(
  --prefix="$PREFIX" --arch=x86_64 --target-os=mingw32 --cross-prefix=$HOST- --enable-cross-compile
  --pkg-config=pkg-config --pkg-config-flags=--static
  --extra-cflags="-I$PREFIX/include" --extra-ldflags="-L$PREFIX/lib -static"   # (-static-libgcc/-libstdc++ en plus = doublons libgcc)
  --extra-libs="-lws2_32 -lcrypt32 -lbcrypt -lstdc++ -lpthread"
  --enable-gpl --enable-version3
  --enable-libx264 --enable-libopus --enable-libsrt --enable-openssl --enable-amf --enable-nvenc
  --enable-static --disable-shared --disable-debug --disable-doc --disable-ffplay --disable-sdl2
  --enable-runtime-cpudetect
)
FF="$BUILD/src/ffmpeg-$FFMPEG_VERSION"
(cd "$FF" && make distclean >/dev/null 2>&1 || true)
(cd "$FF" && ./configure "${FFMPEG_CONFIGURE[@]}" > "$BUILD/ffmpeg-configure.log" 2>&1 \
  || { tail -20 "$BUILD/ffmpeg-configure.log"; tail -40 "$FF/ffbuild/config.log"; exit 1; })
(cd "$FF" && make -j"$JOBS" > "$BUILD/ffmpeg-make.log" 2>&1 || { tail -30 "$BUILD/ffmpeg-make.log"; exit 1; })
cp "$FF/ffmpeg.exe" "$OUT/ffmpeg.exe"; cp "$FF/ffprobe.exe" "$OUT/ffprobe.exe"
$HOST-strip "$OUT/ffmpeg.exe" "$OUT/ffprobe.exe" 2>/dev/null || true

step "licences + sources correspondantes"
LIC="$OUT/THIRD-PARTY-LICENSES"; rm -rf "$LIC"; mkdir -p "$LIC"
cp "$FF/COPYING.GPLv3" "$LIC/ffmpeg-COPYING.GPLv3"
cp "$FF/LICENSE.md" "$LIC/ffmpeg-LICENSE.md"
cp "$SRC/x264/COPYING" "$LIC/x264-COPYING.GPLv2"
cp "$BUILD/src/opus-$OPUS_VERSION/COPYING" "$LIC/opus-COPYING.BSD"
cp "$BUILD/src/srt-$SRT_VERSION/LICENSE" "$LIC/srt-LICENSE.MPL-2.0"
cp "$BUILD/src/openssl-$OPENSSL_VERSION/LICENSE.txt" "$LIC/openssl-LICENSE.Apache-2.0"
awk '/\/\*/{f=1} f{print} /\*\//{if(f)exit}' "$SRC/nv-codec-headers/include/ffnvcodec/nvEncodeAPI.h" > "$LIC/nv-codec-headers-LICENSE.MIT"   # 1er bloc de commentaire = notice MIT
cp "$SRC/AMF/LICENSE.txt" "$LIC/AMF-LICENSE.MIT"
cat > "$LIC/SOURCES.txt" <<EOF
ffmpeg $FFMPEG_VERSION for WebDiffusion PCR (Windows x64) — built $(date -u +%Y-%m-%dT%H:%M:%SZ) by scripts/package/build-ffmpeg-win.sh
(cross-compiled with mingw-w64 $($HOST-gcc -dumpversion) from macOS). License of this binary: GNU GPL version 3 or later
(ffmpeg --enable-gpl --enable-version3). No "nonfree" component. Fully static: no DLL outside Windows itself.

Components and sources (the corresponding source archives are published next to the application updates,
see docs/DEPLOYMENT.md § "Licences tierces") :
  ffmpeg            $FFMPEG_VERSION     $SRC_FFMPEG                        GPL-3.0-or-later
  x264              $X264_COMMIT  $SRC_X264 (branch $X264_REF)   GPL-2.0-or-later
  opus              $OPUS_VERSION     $SRC_OPUS                          BSD-3-Clause
  srt               $SRT_VERSION     $SRC_SRT                           MPL-2.0
  openssl           $OPENSSL_VERSION     $SRC_OPENSSL                       Apache-2.0
  nv-codec-headers  $NVHDR_REF  $SRC_NVHDR (headers only)         MIT
  AMF (headers)     $AMF_REF    $SRC_AMF (amf/public/include)     MIT

ffmpeg configure: ${FFMPEG_CONFIGURE[*]}
EOF
SRCBUNDLE="$PACK/.cache/ffmpeg-sources-$FFMPEG_VERSION"; mkdir -p "$SRCBUNDLE"
for a in "openssl-$OPENSSL_VERSION.tar.gz" "srt-$SRT_VERSION.tar.gz" "opus-$OPUS_VERSION.tar.gz" "ffmpeg-$FFMPEG_VERSION.tar.xz"; do
  [ -f "$SRCBUNDLE/$a" ] || cp "$SRC/$a" "$SRCBUNDLE/"
done
[ -f "$SRCBUNDLE/x264-$X264_COMMIT.tar.gz" ] || git -C "$SRC/x264" archive --format=tar.gz --prefix="x264-$X264_COMMIT/" -o "$SRCBUNDLE/x264-$X264_COMMIT.tar.gz" HEAD
git -C "$SRC/nv-codec-headers" archive --format=tar.gz --prefix="nv-codec-headers-$NVHDR_REF/" -o "$SRCBUNDLE/nv-codec-headers-$NVHDR_REF.tar.gz" HEAD
(cd "$SRC/AMF" && tar czf "$SRCBUNDLE/AMF-headers-$AMF_REF.tar.gz" --transform "s,^,AMF-headers-$AMF_REF/," LICENSE.txt amf/public/include 2>/dev/null \
  || tar czf "$SRCBUNDLE/AMF-headers-$AMF_REF.tar.gz" -s ",^,AMF-headers-$AMF_REF/," LICENSE.txt amf/public/include)
cp "$ROOT/scripts/package/build-ffmpeg-win.sh" "$SRCBUNDLE/"; cp "$LIC/SOURCES.txt" "$SRCBUNDLE/SOURCES-win-x64.txt"
echo "sources correspondantes : $SRCBUNDLE"

step "vérification"
check_binary
