#!/usr/bin/env just --justfile
# OBS Studio plugin for MoQ. See doc/bin/obs.md for the full build guide.
#
# Linux:   `nix develop` provides obs-studio/qt6/ffmpeg/cmake, then `just obs build`.
# macOS:   native, NOT nix. Needs full Xcode; run outside `nix develop` (its
#          toolchain breaks the Xcode build). `just obs setup` downloads
#          libobs/Qt6/ffmpeg via buildspec.json (obs-deps).
# Windows: needs Visual Studio 2022; same buildspec download (run from Git Bash).
#
# libmoq is built from the in-tree crate (rs/libmoq) via cargo. MOQ_LOCAL points
# CMake at the repo root by default, so there's no prebuilt release to download.

set quiet

# List all of the available commands.
default:
    just --list

# Configure via CMake presets. MOQ_LOCAL defaults to the repo root inside
# CMakeLists.txt (so libmoq builds from rs/libmoq); pass `path=/some/moq` to
# override. We deliberately don't compute the path here: `justfile_directory()`
# resolves to the root justfile when this runs as `just obs setup`, so the

# relative math would point outside the repo.
setup preset="" path="":
    #!/usr/bin/env bash
    set -euo pipefail
    PRESET=$(just preset "{{ preset }}")
    if [ -n "{{ path }}" ]; then
        echo "Configuring with preset: $PRESET and MOQ_LOCAL={{ path }}"
        cmake --preset "$PRESET" -DMOQ_LOCAL="{{ path }}"
    else
        echo "Configuring with preset: $PRESET (MOQ_LOCAL defaults to the repo root)"
        cmake --preset "$PRESET"
    fi

# Build via CMake presets. Run `just obs setup` first (it configures + downloads

# deps); not chained here because on macOS setup reconfigures OBS, which is slow.
build preset="":
    #!/usr/bin/env bash
    set -euo pipefail
    PRESET=$(just preset "{{ preset }}")
    cmake --build --preset "$PRESET"

# Copy the freshly built plugin into the OBS user plugin dir and launch OBS.

# Uses the installed OBS (no local OBS build required). macOS only for now.
run:
    #!/usr/bin/env bash
    set -euo pipefail
    if [[ "$OSTYPE" != "darwin"* ]]; then
        echo "just run is macOS-only for now; copy build_*/obs-moq.* into your OBS plugin dir manually" >&2
        exit 1
    fi
    dest="$HOME/Library/Application Support/obs-studio/plugins"
    mkdir -p "$dest"
    cp -a build_macos/RelWithDebInfo/obs-moq.plugin "$dest/"
    RUST_LOG=debug RUST_BACKTRACE=1 OBS_LOG_LEVEL=debug /Applications/OBS.app/Contents/MacOS/OBS

# Unit-test the plugin sources against stubbed libobs/libmoq, under ThreadSanitizer.
#
# Manual, like `just rs macos` and `just rs windows`: PR CI never compiles this
# plugin, and the libobs headers come from the multi-hundred-MB obs-deps download
# that `just obs setup` performs. Run it whenever you touch src/, especially the
# session callback plumbing, whose orderings the build can't check.
test:
    #!/usr/bin/env bash
    set -euo pipefail
    # Unlike the lint recipes, this one never skips: a test gate that reports
    # success without running anything is worse than no gate, and nothing else
    # covers this code.
    cxx="${CXX:-c++}"
    unsupported="'$cxx' cannot build with -fsanitize=thread. These tests need a Clang or GCC
    compiler that supports ThreadSanitizer: set CXX, or on Windows run them from WSL, since
    neither MSVC nor Clang on Windows implements ThreadSanitizer."
    if ! command -v "$cxx" >/dev/null; then
        echo "no C++ compiler at '$cxx'." >&2
        echo "$unsupported" >&2
        exit 1
    fi
    if ! printf 'int main(){}\n' | "$cxx" -x c++ -fsanitize=thread -o /dev/null - >/dev/null 2>&1; then
        echo "$unsupported" >&2
        exit 1
    fi

    # libobs headers: the obs-deps framework (macOS/Windows), the OBS sources
    # CMake unpacks beside it, or a system install (Linux/nix).
    obs_include=""
    for candidate in \
        .deps/Frameworks/libobs.framework/Versions/A/Headers \
        .deps/obs-studio-*/libobs \
        "${OBS_INCLUDE_DIR:-}"; do
        if [ -n "$candidate" ] && [ -f "$candidate/obs.h" ]; then
            obs_include="$candidate"
            break
        fi
    done
    if [ -z "$obs_include" ] && command -v pkg-config >/dev/null && pkg-config --exists libobs; then
        obs_include=$(pkg-config --variable=includedir libobs)/obs
    fi
    if [ -z "$obs_include" ]; then
        echo "libobs headers not found; run 'just obs setup' (or set OBS_INCLUDE_DIR)" >&2
        exit 1
    fi

    # moq.h is generated by cbindgen when libmoq builds.
    moq_include="../../target/include"
    if [ ! -f "$moq_include/moq.h" ]; then
        echo "$moq_include/moq.h missing; run 'just obs build' or 'cargo build -p libmoq' first" >&2
        exit 1
    fi

    out=$(mktemp -d)
    trap 'rm -rf "$out"' EXIT
    echo "Building tests against $obs_include"
    "$cxx" -std=c++17 -g -O0 -fsanitize=thread \
        -I "$obs_include" -I src -I "$moq_include" \
        -o "$out/moq-output-test" test/moq-output-test.cpp src/moq-output.cpp
    TSAN_OPTIONS="halt_on_error=1" "$out/moq-output-test"

# Lint formatting. Skips a tool silently if it isn't on $PATH (matches repo convention).
check:
    #!/usr/bin/env bash
    set -euo pipefail
    if grep -Fq '"MOQ_VERSION"' CMakePresets.json; then
        echo "CMakePresets.json must not pin MOQ_VERSION" >&2
        exit 1
    fi
    if command -v cmake >/dev/null; then
        build_dir=$(mktemp -d)
        trap 'rm -rf "$build_dir"' EXIT
        if cmake -S . -B "$build_dir" -DMOQ_LOCAL= >"$build_dir/configure.log" 2>&1; then
            echo "CMake accepted a release build without MOQ_VERSION" >&2
            exit 1
        fi
        if ! grep -Fq "MOQ_VERSION is required when MOQ_LOCAL does not contain rs/libmoq" "$build_dir/configure.log"; then
            cat "$build_dir/configure.log" >&2
            exit 1
        fi
    fi
    if command -v clang-format >/dev/null; then
        git ls-files 'src/*.cpp' 'src/*.h' 'test/*.cpp' | xargs clang-format --dry-run --Werror
    fi
    if command -v gersemi >/dev/null; then
        gersemi --check CMakeLists.txt cmake
    fi

# Auto-fix formatting.
fix:
    #!/usr/bin/env bash
    set -euo pipefail
    if command -v clang-format >/dev/null; then
        git ls-files 'src/*.cpp' 'src/*.h' 'test/*.cpp' | xargs clang-format -i
    fi
    if command -v gersemi >/dev/null; then
        gersemi --in-place CMakeLists.txt cmake
    fi

# Detect the CMake preset for the current platform (or use the override).
preset override="":
    #!/usr/bin/env bash
    set -euo pipefail
    if [[ -n "{{ override }}" ]]; then
        echo "{{ override }}"
    elif [[ "$OSTYPE" == "darwin"* ]]; then
        echo "macos"
    elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
        echo "ubuntu-x86_64"
    elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then
        echo "windows-x64"
    else
        echo "Unknown platform: $OSTYPE" >&2
        exit 1
    fi
