#!/usr/bin/env bash
#
# build-ffmpeg.sh
#
# Configures and builds FFmpeg 8.1.2 itself against the dependencies built by
# build-dependencies.sh, inside an MSYS2 UCRT64 shell.
#
# Run via scripts/build.ps1, which extracts the pinned FFmpeg source and
# invokes this script with the paths below (MSYS POSIX form) and the
# checked-in configure-args file. This script's only job is to apply that
# file plus the path-dependent flags that cannot live in a checked-in file
# (AMF include path, dependency pkg-config path, install prefix) -- it does
# not choose or invent any capability flags itself.
#
# Usage:
#   build-ffmpeg.sh <ffmpeg_source_dir> <deps_prefix> <amf_headers_dir> \
#       <configure_args_file> <dist_prefix>
#
# Produces, under <dist_prefix>:
#   bin/ffmpeg.exe
# and under <ffmpeg_source_dir>:
#   ffbuild/config.log, ffbuild/config.h (FFmpeg's own configure logs --
#   note the ffbuild/ subdirectory, not the source root)
#   ffbuild-configure.log, ffbuild-manifest.txt (this script's own logs:
#   compiler/linker/assembler versions and the exact resolved configure
#   command line, for the release manifest)

set -euo pipefail

if [ "$#" -ne 5 ]; then
    echo "usage: $0 <ffmpeg_source_dir> <deps_prefix> <amf_headers_dir> <configure_args_file> <dist_prefix>" >&2
    exit 2
fi

FFMPEG_DIR="$1"
DEPS_PREFIX="$2"
AMF_HEADERS_DIR="$3"
ARGS_FILE="$4"
DIST_PREFIX="$5"

[ -d "$FFMPEG_DIR" ]      || { echo "ERROR: FFmpeg source dir not found: $FFMPEG_DIR" >&2; exit 1; }
[ -d "$DEPS_PREFIX" ]     || { echo "ERROR: deps prefix not found: $DEPS_PREFIX" >&2; exit 1; }
[ -d "$AMF_HEADERS_DIR" ] || { echo "ERROR: AMF headers dir not found: $AMF_HEADERS_DIR" >&2; exit 1; }
[ -f "$ARGS_FILE" ]       || { echo "ERROR: configure args file not found: $ARGS_FILE" >&2; exit 1; }
[ -f "$AMF_HEADERS_DIR/AMF/core/Version.h" ] || {
    echo "ERROR: $AMF_HEADERS_DIR does not look like the AMF headers root (AMF/core/Version.h missing)" >&2
    exit 1
}

mkdir -p "$DIST_PREFIX"
NPROC="$(nproc 2>/dev/null || echo 4)"
MANIFEST="$FFMPEG_DIR/ffbuild-manifest.txt"
: > "$MANIFEST"
log() { echo "$@" | tee -a "$MANIFEST"; }

# Strip comments/blank lines from the checked-in args file, preserving order.
mapfile -t FILE_ARGS < <(grep -vE '^[[:space:]]*(#|$)' "$ARGS_FILE")

PATH_ARGS=(
    "--prefix=$DIST_PREFIX"
    "--extra-cflags=-I$AMF_HEADERS_DIR"
)

export PKG_CONFIG_PATH="$DEPS_PREFIX/lib/pkgconfig"

log "=== Toolchain ==="
log "gcc:  $(gcc --version | head -n1)"
log "ld:   $(ld --version | head -n1)"
log "as (nasm): $(nasm -v)"
log "PKG_CONFIG_PATH=$PKG_CONFIG_PATH"
log ""

cd "$FFMPEG_DIR"

log "=== Configure ==="
log "Resolved command line:"
{
    printf './configure'
    printf ' \\\n    %q' "${PATH_ARGS[@]}" "${FILE_ARGS[@]}"
    printf '\n'
} | tee -a "$MANIFEST"

./configure "${PATH_ARGS[@]}" "${FILE_ARGS[@]}" 2>&1 | tee ffbuild-configure.log
CONFIGURE_STATUS=${PIPESTATUS[0]}
if [ "$CONFIGURE_STATUS" -ne 0 ]; then
    echo "ERROR: FFmpeg configure failed (exit $CONFIGURE_STATUS). See $FFMPEG_DIR/ffbuild-configure.log and $FFMPEG_DIR/ffbuild/config.log." >&2
    exit "$CONFIGURE_STATUS"
fi
log "configure: OK"
log ""

log "=== Build ==="
make -j"$NPROC" 2>&1 | tee ffbuild-make.log
log "make: OK"
log ""

log "=== Install ==="
make install
log "install: OK -- $DIST_PREFIX/bin/ffmpeg.exe"
log ""

if [ ! -f "$DIST_PREFIX/bin/ffmpeg.exe" ]; then
    echo "ERROR: build reported success but $DIST_PREFIX/bin/ffmpeg.exe does not exist." >&2
    exit 1
fi

log "=== Check: no MSYS2/MinGW runtime DLL dependencies ==="
# --extra-ldflags=-static (in config/ffmpeg.configure.args) exists specifically
# to prevent this: a binary that dynamically links libstdc++/libgcc_s/
# libwinpthread/msys-2.0 will crash with exit code -1073741515
# (0xC0000135 STATUS_DLL_NOT_FOUND) the moment it's run outside the MSYS2
# shell that built it -- exactly the failure Milestone 2 hit before this
# flag was added, and exactly what "runs on a clean Windows install without
# MSYS2" (the plan's Milestone 2 exit criterion) rules out. Catch it here
# with a clear message rather than a cryptic exit code discovered later
# during verify-binary.ps1/test.ps1.
BAD_DLLS='libstdc\+\+|libgcc_s|libwinpthread|msys-2\.0'
FOUND_BAD=$(objdump -p "$DIST_PREFIX/bin/ffmpeg.exe" | grep -iE '^\s*DLL Name:' | grep -iE "$BAD_DLLS" || true)
if [ -n "$FOUND_BAD" ]; then
    echo "ERROR: ffmpeg.exe dynamically depends on MSYS2/MinGW runtime DLL(s) that will not exist on a clean Windows install:" >&2
    echo "$FOUND_BAD" >&2
    echo "Expected --extra-ldflags=-static (config/ffmpeg.configure.args) to eliminate these -- check it took effect in the configure line above." >&2
    exit 1
fi
log "No MSYS2/MinGW runtime DLL dependencies found."
log ""

log "=== Strip (Milestone 4 minimisation) ==="
# Symbol table / debug info only help a debugger attached to this exact
# build; removing them does not change behaviour. Run after the DLL check
# above, not before, so a build that's broken in a way strip could mask
# (unlikely, but the DLL check needs an intact binary to inspect via
# objdump) is still caught first.
SIZE_BEFORE=$(stat -c%s "$DIST_PREFIX/bin/ffmpeg.exe" 2>/dev/null || stat -f%z "$DIST_PREFIX/bin/ffmpeg.exe")
strip --strip-all "$DIST_PREFIX/bin/ffmpeg.exe"
SIZE_AFTER=$(stat -c%s "$DIST_PREFIX/bin/ffmpeg.exe" 2>/dev/null || stat -f%z "$DIST_PREFIX/bin/ffmpeg.exe")
log "Stripped: $SIZE_BEFORE -> $SIZE_AFTER bytes"
log ""

log "=== Result ==="
log "Binary: $DIST_PREFIX/bin/ffmpeg.exe"
log "Build manifest: $MANIFEST"
