#!/usr/bin/env bash

# This script uses bash 4+ features (mapfile, safe empty-array expansion under
# `set -u`). macOS ships bash 3.2, so re-exec under a newer bash when one is
# present (Homebrew), and fail with a clear message otherwise.
if [ "${BASH_VERSINFO:-0}" -lt 4 ]; then
    for _newer_bash in /opt/homebrew/bin/bash /usr/local/bin/bash; do
        [ -x "$_newer_bash" ] && exec "$_newer_bash" "$0" "$@"
    done
    echo "ERROR: build-lite-backend-artifact.sh requires bash 4+ (found ${BASH_VERSION:-unknown})." >&2
    echo "       On macOS: brew install bash" >&2
    exit 1
fi

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

ABI_VERSION="sdxl-c-v1"
LINK_MODE="imported"
BACKEND_DIR="$PROJECT_ROOT/third_party/silentdragonxlite/lib"
BACKEND_SOURCE_DIR=""
BUILD_BACKEND_DIR=""
BACKEND_DEPENDENCY_DIR=""
BACKEND_DEPENDENCY_OVERRIDE_REQUESTED=false
OUT_DIR="$PROJECT_ROOT/build/lite-backend"
PLATFORM=""
RUST_TARGET=""
CARGO_TARGET_DIR_VALUE="${CARGO_TARGET_DIR:-}"
ARTIFACT_PATH=""
BUILD_ARTIFACT=true
BUILDER="${DRAGONX_LITE_BACKEND_BUILDER:-local}"
JOBS="${JOBS:-}"
SOURCE_DATE_EPOCH_VALUE="${SOURCE_DATE_EPOCH:-}"
REPRODUCIBLE=false
SIGNATURE_REQUIRED=false
SIGNATURE_FILE=""
SIGNATURE_FORMAT=""
SIGNATURE_VERIFICATION_TOOL=""
SIGNATURE_VERIFICATION_COMMAND=""
SIGNATURE_KEY_FINGERPRINT=""
SIGNATURE_CERTIFICATE_IDENTITY=""
SIGNATURE_CERTIFICATE_ISSUER=""
SIGNATURE_TRANSPARENCY_LOG_URL=""
SIGNATURE_VERIFIED_SHA256=""
SIGNATURE_POLICY_NAME="dragonx-lite-backend-signature-policy-v1"
SIGNATURE_POLICY_DEFINED_MANIFEST_VALUE=true
SIGNATURE_REQUIRED_MANIFEST_VALUE=false
SIGNATURE_METADATA_PROVIDED=false
SIGNATURE_VERIFICATION_PERFORMED=false
SIGNATURE_VERIFICATION_STATUS="not-provided"
SIGNATURE_FILE_SHA256=""

REQUIRED_SYMBOLS=(
    litelib_wallet_exists
    litelib_initialize_new
    litelib_initialize_new_from_phrase
    litelib_initialize_existing
    litelib_execute
    litelib_rust_free_string
    litelib_check_server_online
    litelib_shutdown
)

EXTRA_CARGO_ARGS=()
EXTRA_REMAP_PATH_PREFIXES=()

usage() {
    cat <<EOF
Build or inventory the SDXL-compatible lite backend artifact.

Usage: $0 [options]

Options:
    --platform linux|windows|macos  Artifact platform. Defaults to host platform.
    --rust-target TRIPLE            Cargo target triple for cross builds.
    --cargo-target-dir PATH         Isolated Cargo target directory for clean builds.
    --backend-dir PATH              SilentDragonXLite/lib source directory.
    --silentdragonxlitelib-dir PATH Override the wrapper's silentdragonxlitelib dependency path.
    --out-dir PATH                  Output directory for copied artifact and metadata.
    --reproducible                  Add deterministic Rust path remaps for clean builds.
    --remap-path-prefix FROM=TO     Extra rustc path remap used with --reproducible.
    --builder NAME                  Redacted builder/provenance label. Default: local.
    -j, --jobs N                    Cargo parallel jobs.
    --cargo-arg ARG                 Extra argument forwarded to cargo build.
    -h, --help                      Show this help.

Outputs:
  <out>/<platform>/<artifact>
  <out>/<platform>/lite-backend-symbols.txt
  <out>/<platform>/lite-backend-artifact-manifest.json

The lite backend is always built from the vendored in-tree source
(third_party/silentdragonxlite), which is the trust root. Prebuilt artifacts
and self-attested signature metadata are NOT accepted (F15-1) — the previous
scheme only recorded an unverified "verified" claim. The script captures the
freshly-built artifact's symbols and checksum, and records build provenance.
It does not load the library, resolve function pointers, call SDXL, sign,
upload, or publish artifacts.
EOF
}

info() { printf '[lite-backend] %s\n' "$*"; }
warn() { printf '[lite-backend] warning: %s\n' "$*" >&2; }
die() { printf '[lite-backend] ERROR: %s\n' "$*" >&2; exit 1; }

absolute_path() {
    local path="$1"
    if [[ "$path" = /* ]]; then
        printf '%s\n' "$path"
    else
        printf '%s/%s\n' "$PWD" "$path"
    fi
}

host_platform() {
    case "$(uname -s)" in
        Linux) printf 'linux\n' ;;
        Darwin) printf 'macos\n' ;;
        MINGW*|MSYS*|CYGWIN*) printf 'windows\n' ;;
        *) die "unsupported host platform: $(uname -s)" ;;
    esac
}

normalize_platform() {
    case "$1" in
        linux|Linux) printf 'linux\n' ;;
        windows|win|Win|Windows) printf 'windows\n' ;;
        macos|mac|darwin|Darwin) printf 'macos\n' ;;
        "") host_platform ;;
        *) die "unsupported platform: $1" ;;
    esac
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        --platform)
            [[ $# -ge 2 ]] || die "--platform requires a value"
            PLATFORM="$(normalize_platform "$2")"
            shift 2
            ;;
        --rust-target)
            [[ $# -ge 2 ]] || die "--rust-target requires a value"
            RUST_TARGET="$2"
            shift 2
            ;;
        --cargo-target-dir)
            [[ $# -ge 2 ]] || die "--cargo-target-dir requires a value"
            CARGO_TARGET_DIR_VALUE="$(absolute_path "$2")"
            shift 2
            ;;
        --backend-dir)
            [[ $# -ge 2 ]] || die "--backend-dir requires a value"
            BACKEND_DIR="$(absolute_path "$2")"
            shift 2
            ;;
        --silentdragonxlitelib-dir)
            [[ $# -ge 2 ]] || die "--silentdragonxlitelib-dir requires a value"
            BACKEND_DEPENDENCY_DIR="$(absolute_path "$2")"
            BACKEND_DEPENDENCY_OVERRIDE_REQUESTED=true
            shift 2
            ;;
        --out-dir)
            [[ $# -ge 2 ]] || die "--out-dir requires a value"
            OUT_DIR="$(absolute_path "$2")"
            shift 2
            ;;
        --artifact|--no-build)
            die "$1 was removed (F15-1): the lite backend must be built from the vendored in-tree source (third_party/silentdragonxlite); prebuilt artifacts are no longer accepted."
            ;;
        --reproducible)
            REPRODUCIBLE=true
            shift
            ;;
        --remap-path-prefix)
            [[ $# -ge 2 ]] || die "--remap-path-prefix requires FROM=TO"
            [[ "$2" == *=* ]] || die "--remap-path-prefix requires FROM=TO"
            EXTRA_REMAP_PATH_PREFIXES+=("$2")
            shift 2
            ;;
        --builder)
            [[ $# -ge 2 ]] || die "--builder requires a value"
            BUILDER="$2"
            shift 2
            ;;
        --signature-required|--signature-file|--signature-path|--signature-format|\
--signature-verification-tool|--signature-tool|--signature-verification-command|\
--signature-key-fingerprint|--signature-certificate-identity|--signature-certificate-issuer|\
--signature-transparency-log-url|--signature-verified-sha256)
            die "signature-attestation flags were removed (F15-1): they recorded a self-attested \"verified\" claim without running any cryptographic verifier. The lite backend is built from the vendored in-tree source, which is the trust root."
            ;;
        -j|--jobs)
            [[ $# -ge 2 ]] || die "--jobs requires a value"
            JOBS="$2"
            shift 2
            ;;
        --cargo-arg)
            [[ $# -ge 2 ]] || die "--cargo-arg requires a value"
            EXTRA_CARGO_ARGS+=("$2")
            shift 2
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *) die "unknown option: $1" ;;
    esac
done

PLATFORM="$(normalize_platform "$PLATFORM")"
BACKEND_SOURCE_DIR="$BACKEND_DIR"
BUILD_BACKEND_DIR="$BACKEND_SOURCE_DIR"

if [[ "$PLATFORM" == "windows" && -z "$RUST_TARGET" ]]; then
    RUST_TARGET="x86_64-pc-windows-gnu"
fi
if [[ "$PLATFORM" == "macos" && -z "$RUST_TARGET" && "$(host_platform)" != "macos" ]]; then
    die "macOS artifacts require --rust-target when not running on macOS"
fi
if [[ "$BUILD_ARTIFACT" == false && -z "$ARTIFACT_PATH" ]]; then
    die "--no-build requires --artifact"
fi

backend_dependency_path_from_cargo() {
    local cargo_toml="$1"
    awk '
        /^[[:space:]]*silentdragonxlitelib[[:space:]]*=/ {
            original = $0
            path = $0
            sub(/.*path[[:space:]]*=[[:space:]]*"/, "", path)
            sub(/".*/, "", path)
            if (path != original) print path
            exit
        }
    ' "$cargo_toml"
}

canonical_dependency_path() {
    local path="$1"
    if [[ -d "$path" ]]; then
        (cd "$path" && pwd -P)
    else
        absolute_path "$path"
    fi
}

validate_backend_dependency_source() {
    [[ -n "$BACKEND_DEPENDENCY_DIR" ]] || return

    if [[ ! -f "$BACKEND_DEPENDENCY_DIR/Cargo.toml" ]]; then
        if [[ "$BUILD_ARTIFACT" == true || "$BACKEND_DEPENDENCY_OVERRIDE_REQUESTED" == true ]]; then
            die "Cargo.toml not found in $BACKEND_DEPENDENCY_DIR"
        fi
        warn "Cargo.toml not found in silentdragonxlitelib source: $BACKEND_DEPENDENCY_DIR"
        return
    fi

    if ! grep -Eq '^[[:space:]]*name[[:space:]]*=[[:space:]]*"silentdragonxlitelib"' "$BACKEND_DEPENDENCY_DIR/Cargo.toml"; then
        if [[ "$BUILD_ARTIFACT" == true || "$BACKEND_DEPENDENCY_OVERRIDE_REQUESTED" == true ]]; then
            die "dependency path does not look like silentdragonxlitelib: $BACKEND_DEPENDENCY_DIR"
        fi
        warn "dependency path does not look like silentdragonxlitelib: $BACKEND_DEPENDENCY_DIR"
    fi
}

# Ensure the Sapling proving params are present in the core crate (rust-embed bakes them in at build
# time). They are the fixed Zcash trusted-setup output — not buildable — so fetch + verify them from
# git.dragonx.is when absent. Override the source with SAPLING_PARAMS_BASE_URL.
SAPLING_PARAMS_BASE_URL="${SAPLING_PARAMS_BASE_URL:-https://git.dragonx.is/DragonX/zcash-params/releases/download/sapling-v1}"
ensure_sapling_params() {
    local dir="$1"
    [[ -n "$dir" ]] || return 0
    mkdir -p "$dir"
    local specs=(
        "sapling-spend.params:8e48ffd23abb3a5fd9c5589204f32d9c31285a04b78096ba40a79b75677efc13"
        "sapling-output.params:2f0ebbcbb9bb0bcffe95a397e7eba89c29eb4dde6191c339db88570e3f3fb0e4"
    )
    local spec name want path got
    for spec in "${specs[@]}"; do
        name="${spec%%:*}"; want="${spec##*:}"; path="$dir/$name"
        if [[ -f "$path" ]] && [[ "$(compute_sha256 "$path")" == "$want" ]]; then
            info "sapling param present and verified: $name"
            continue
        fi
        info "fetching $name from $SAPLING_PARAMS_BASE_URL"
        curl -fsSL "$SAPLING_PARAMS_BASE_URL/$name" -o "$path" || die "failed to download sapling param: $name"
        got="$(compute_sha256 "$path")"
        [[ "$got" == "$want" ]] || { rm -f "$path"; die "sapling param $name sha256 mismatch (got $got, want $want)"; }
        info "downloaded and verified $name"
    done
}

prepare_backend_source() {
    BUILD_BACKEND_DIR="$BACKEND_SOURCE_DIR"

    if [[ "$BACKEND_DEPENDENCY_OVERRIDE_REQUESTED" == false ]]; then
        if [[ -f "$BACKEND_SOURCE_DIR/Cargo.toml" ]]; then
            local configured_dependency_path
            configured_dependency_path="$(backend_dependency_path_from_cargo "$BACKEND_SOURCE_DIR/Cargo.toml")"
            if [[ -n "$configured_dependency_path" ]]; then
                if [[ "$configured_dependency_path" = /* ]]; then
                    BACKEND_DEPENDENCY_DIR="$(canonical_dependency_path "$configured_dependency_path")"
                    warn "backend Cargo.toml uses an absolute silentdragonxlitelib path; use --silentdragonxlitelib-dir for portable builders"
                else
                    BACKEND_DEPENDENCY_DIR="$(canonical_dependency_path "$BACKEND_SOURCE_DIR/$configured_dependency_path")"
                    info "using relative silentdragonxlitelib dependency at $BACKEND_DEPENDENCY_DIR"
                fi
                validate_backend_dependency_source
            fi
        fi
        return
    fi

    [[ -f "$BACKEND_SOURCE_DIR/Cargo.toml" ]] || die "Cargo.toml not found in $BACKEND_SOURCE_DIR"
    validate_backend_dependency_source
    [[ "$BACKEND_DEPENDENCY_DIR" != *\"* ]] || die "--silentdragonxlitelib-dir path cannot contain a double quote"

    local prepared_root="$OUT_DIR/.prepared-backend/$PLATFORM"
    [[ "$prepared_root" == */.prepared-backend/* ]] || die "refusing unsafe prepared backend path: $prepared_root"
    rm -rf "$prepared_root"
    mkdir -p "$prepared_root"

    ln -s "$BACKEND_SOURCE_DIR/src" "$prepared_root/src"
    [[ -f "$BACKEND_SOURCE_DIR/Cargo.lock" ]] && ln -s "$BACKEND_SOURCE_DIR/Cargo.lock" "$prepared_root/Cargo.lock"
    [[ -d "$BACKEND_SOURCE_DIR/.cargo" ]] && ln -s "$BACKEND_SOURCE_DIR/.cargo" "$prepared_root/.cargo"
    # Honor the pinned Rust toolchain (rust-toolchain.toml) inside the prepared root too,
    # so builds using --silentdragonxlitelib-dir still select rustc 1.63.
    [[ -f "$BACKEND_SOURCE_DIR/rust-toolchain.toml" ]] && ln -s "$BACKEND_SOURCE_DIR/rust-toolchain.toml" "$prepared_root/rust-toolchain.toml"
    [[ -d "$BACKEND_SOURCE_DIR/libsodium-mingw" ]] && ln -s "$BACKEND_SOURCE_DIR/libsodium-mingw" "$prepared_root/libsodium-mingw"
    # Vendored crate deps (offline builds): the .cargo/config.toml's vendored-sources directory is
    # "vendor" relative to the build root, so expose it inside the prepared root too.
    [[ -d "$BACKEND_SOURCE_DIR/vendor" ]] && ln -s "$BACKEND_SOURCE_DIR/vendor" "$prepared_root/vendor"
    [[ -f "$BACKEND_SOURCE_DIR/silentdragonxlitelib.h" ]] && ln -s "$BACKEND_SOURCE_DIR/silentdragonxlitelib.h" "$prepared_root/silentdragonxlitelib.h"

    local replacement="silentdragonxlitelib = { path = \"$BACKEND_DEPENDENCY_DIR\" }"
    awk -v replacement="$replacement" '
        BEGIN { replaced = 0 }
        /^[[:space:]]*silentdragonxlitelib[[:space:]]*=/ {
            print replacement
            replaced = 1
            next
        }
        { print }
        END { if (replaced != 1) exit 42 }
    ' "$BACKEND_SOURCE_DIR/Cargo.toml" > "$prepared_root/Cargo.toml" \
        || die "failed to prepare backend Cargo.toml with portable silentdragonxlitelib path"

    BUILD_BACKEND_DIR="$prepared_root"
    info "prepared backend source at $BUILD_BACKEND_DIR with silentdragonxlitelib from $BACKEND_DEPENDENCY_DIR"
}

prepare_backend_source

artifact_kind() {
    local name="${1##*/}"
    case "$name" in
        *.a|*.lib) printf 'static-library\n' ;;
        *.so|*.dylib|*.dll) printf 'shared-library\n' ;;
        *) printf 'unknown\n' ;;
    esac
}

cargo_output_candidates() {
    local cargo_target_root="$BUILD_BACKEND_DIR/target"
    if [[ -n "$CARGO_TARGET_DIR_VALUE" ]]; then
        cargo_target_root="$CARGO_TARGET_DIR_VALUE"
    fi

    local base="$cargo_target_root/release"
    if [[ -n "$RUST_TARGET" ]]; then
        base="$cargo_target_root/$RUST_TARGET/release"
    fi

    case "$PLATFORM" in
        linux)
            printf '%s\n' "$base/libsilentdragonxlite.a" "$base/silentdragonxlite.a" "$base/libsilentdragonxlite.so"
            ;;
        windows)
            printf '%s\n' "$base/silentdragonxlite.lib" "$base/libsilentdragonxlite.a" "$base/silentdragonxlite.dll"
            ;;
        macos)
            printf '%s\n' "$base/libsilentdragonxlite.a" "$base/silentdragonxlite.a" "$base/libsilentdragonxlite.dylib" "$base/silentdragonxlite.dylib"
            ;;
    esac
}

source_revision_for() {
    local dir="$1"
    local revision_file
    for revision_file in "$dir/DRAGONX_SOURCE_REVISION" "$dir/../DRAGONX_SOURCE_REVISION"; do
        if [[ -f "$revision_file" ]]; then
            sed -n '1p' "$revision_file"
            return
        fi
    done

    if git -C "$dir" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
        git -C "$dir" rev-parse HEAD 2>/dev/null || printf 'unknown'
    else
        printf 'unknown'
    fi
}

default_source_date_epoch() {
    if git -C "$PROJECT_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
        git -C "$PROJECT_ROOT" log -1 --format=%ct 2>/dev/null || printf '0'
    else
        printf '0'
    fi
}

append_rustflag() {
    local rustflag="$1"
    if [[ -n "${RUSTFLAGS:-}" ]]; then
        export RUSTFLAGS="${RUSTFLAGS} ${rustflag}"
    else
        export RUSTFLAGS="$rustflag"
    fi
}

append_rust_path_remap() {
    local from_path="$1"
    local to_path="$2"
    [[ -n "$from_path" && -n "$to_path" ]] || return
    append_rustflag "--remap-path-prefix=${from_path}=${to_path}"
}

apply_reproducible_rustflags() {
    local cargo_target_root="$BUILD_BACKEND_DIR/target"
    if [[ -n "$CARGO_TARGET_DIR_VALUE" ]]; then
        cargo_target_root="$CARGO_TARGET_DIR_VALUE"
    fi

    append_rust_path_remap "$PROJECT_ROOT" "/dragonx-project"
    append_rust_path_remap "$BACKEND_SOURCE_DIR" "/dragonx-lite-backend"
    if [[ "$BUILD_BACKEND_DIR" != "$BACKEND_SOURCE_DIR" ]]; then
        append_rust_path_remap "$BUILD_BACKEND_DIR" "/dragonx-lite-backend"
    fi
    append_rust_path_remap "$BACKEND_DEPENDENCY_DIR" "/dragonx-lite-backend-dependency"
    for path_remap in "${EXTRA_REMAP_PATH_PREFIXES[@]}"; do
        append_rustflag "--remap-path-prefix=${path_remap}"
    done

    local cargo_home="${CARGO_HOME:-}"
    if [[ -z "$cargo_home" && -n "${HOME:-}" ]]; then
        cargo_home="$HOME/.cargo"
    fi
    if [[ -n "$cargo_home" && -d "$cargo_home" ]]; then
        append_rust_path_remap "$cargo_home" "/cargo-home"
    fi
    append_rust_path_remap "$cargo_target_root" "/dragonx-lite-cargo-target"
}

build_with_cargo() {
    command -v cargo >/dev/null 2>&1 || die "cargo was not found"
    [[ -f "$BUILD_BACKEND_DIR/Cargo.toml" ]] || die "Cargo.toml not found in $BUILD_BACKEND_DIR"

    if [[ -z "$SOURCE_DATE_EPOCH_VALUE" ]]; then
        SOURCE_DATE_EPOCH_VALUE="$(default_source_date_epoch)"
    fi

    export CARGO_INCREMENTAL=0
    export SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH_VALUE"
    if [[ -n "$CARGO_TARGET_DIR_VALUE" ]]; then
        export CARGO_TARGET_DIR="$CARGO_TARGET_DIR_VALUE"
    fi
    if [[ "$REPRODUCIBLE" == true ]]; then
        apply_reproducible_rustflags
    fi
    if [[ "$PLATFORM" == "windows" && -d "$BUILD_BACKEND_DIR/libsodium-mingw" ]]; then
        export SODIUM_LIB_DIR="$BUILD_BACKEND_DIR/libsodium-mingw"
    fi

    [[ -n "$BACKEND_DEPENDENCY_DIR" ]] && ensure_sapling_params "$BACKEND_DEPENDENCY_DIR/zcash-params"

    local cargo_cmd=(cargo build --locked --lib --release)
    if [[ -n "$RUST_TARGET" ]]; then
        cargo_cmd+=(--target "$RUST_TARGET")
    fi
    if [[ -n "$JOBS" ]]; then
        cargo_cmd+=(-j "$JOBS")
    fi
    cargo_cmd+=("${EXTRA_CARGO_ARGS[@]}")

    info "building backend in $BUILD_BACKEND_DIR"
    (cd "$BUILD_BACKEND_DIR" && "${cargo_cmd[@]}")

    while IFS= read -r candidate; do
        if [[ -f "$candidate" ]]; then
            ARTIFACT_PATH="$candidate"
            return
        fi
    done < <(cargo_output_candidates)

    die "cargo finished, but no expected backend artifact was found under $BUILD_BACKEND_DIR/target"
}

select_nm_tool() {
    if [[ "$PLATFORM" == "windows" ]] && command -v x86_64-w64-mingw32-nm >/dev/null 2>&1; then
        printf 'x86_64-w64-mingw32-nm\n'
        return
    fi
    if command -v llvm-nm >/dev/null 2>&1; then
        printf 'llvm-nm\n'
        return
    fi
    if command -v nm >/dev/null 2>&1; then
        printf 'nm\n'
        return
    fi
    die "no symbol inventory tool found; install nm, llvm-nm, or x86_64-w64-mingw32-nm"
}

compute_sha256() {
    local file="$1"
    if command -v sha256sum >/dev/null 2>&1; then
        sha256sum "$file" | awk '{print $1}'
    elif command -v shasum >/dev/null 2>&1; then
        shasum -a 256 "$file" | awk '{print $1}'
    else
        die "sha256sum or shasum is required"
    fi
}

json_escape() {
    local value="$1"
    value="${value//\\/\\\\}"
    value="${value//\"/\\\"}"
    value="${value//$'\n'/\\n}"
    value="${value//$'\r'/}"
    value="${value//$'\t'/\\t}"
    printf '"%s"' "$value"
}

json_array() {
    local first=true
    printf '['
    for value in "$@"; do
        if [[ "$first" == true ]]; then
            first=false
        else
            printf ','
        fi
        json_escape "$value"
    done
    printf ']'
}

json_array_from_file() {
    local file="$1"
    local values=()
    if [[ -f "$file" ]]; then
        mapfile -t values < "$file"
    fi
    json_array "${values[@]}"
}

signature_metadata_requested() {
    [[ "$SIGNATURE_REQUIRED" == true || \
       -n "$SIGNATURE_FILE" || \
       -n "$SIGNATURE_FORMAT" || \
       -n "$SIGNATURE_VERIFICATION_TOOL" || \
       -n "$SIGNATURE_VERIFICATION_COMMAND" || \
       -n "$SIGNATURE_KEY_FINGERPRINT" || \
       -n "$SIGNATURE_CERTIFICATE_IDENTITY" || \
       -n "$SIGNATURE_CERTIFICATE_ISSUER" || \
       -n "$SIGNATURE_TRANSPARENCY_LOG_URL" || \
       -n "$SIGNATURE_VERIFIED_SHA256" ]]
}

validate_signature_metadata() {
    SIGNATURE_REQUIRED_MANIFEST_VALUE=false
    if [[ "$SIGNATURE_REQUIRED" == true ]]; then
        SIGNATURE_REQUIRED_MANIFEST_VALUE=true
    fi

    if ! signature_metadata_requested; then
        return
    fi

    [[ -n "$SIGNATURE_FILE" ]] || die "signature metadata requires --signature-file"
    [[ -f "$SIGNATURE_FILE" ]] || die "signature file does not exist: $SIGNATURE_FILE"
    [[ -n "$SIGNATURE_FORMAT" ]] || die "signature metadata requires --signature-format"
    case "$SIGNATURE_FORMAT" in
        minisign|gpg|sigstore|external|other) ;;
        *) die "unsupported --signature-format: $SIGNATURE_FORMAT" ;;
    esac
    [[ -n "$SIGNATURE_VERIFICATION_TOOL" ]] || die "signature metadata requires --signature-verification-tool"
    [[ -n "$SIGNATURE_VERIFIED_SHA256" ]] || die "signature metadata requires --signature-verified-sha256"
    [[ "$SIGNATURE_VERIFIED_SHA256" == "$SHA256_DIGEST" ]] || die "signature verified SHA-256 does not match artifact SHA-256"
    if [[ -z "$SIGNATURE_KEY_FINGERPRINT" && -z "$SIGNATURE_CERTIFICATE_IDENTITY" ]]; then
        die "signature metadata requires --signature-key-fingerprint or --signature-certificate-identity"
    fi

    SIGNATURE_METADATA_PROVIDED=true
    SIGNATURE_VERIFICATION_PERFORMED=true
    SIGNATURE_VERIFICATION_STATUS="verified"
    SIGNATURE_FILE_SHA256="$(compute_sha256 "$SIGNATURE_FILE")"
}

if [[ "$BUILD_ARTIFACT" == true ]]; then
    build_with_cargo
fi
if [[ -z "$SOURCE_DATE_EPOCH_VALUE" ]]; then
    SOURCE_DATE_EPOCH_VALUE="$(default_source_date_epoch)"
fi

[[ -f "$ARTIFACT_PATH" ]] || die "artifact not found: $ARTIFACT_PATH"

KIND="$(artifact_kind "$ARTIFACT_PATH")"
[[ "$KIND" != "unknown" ]] || die "artifact kind is unsupported: $ARTIFACT_PATH"

PLATFORM_OUT_DIR="$OUT_DIR/$PLATFORM"
mkdir -p "$PLATFORM_OUT_DIR"

ARTIFACT_NAME="$(basename "$ARTIFACT_PATH")"
ARTIFACT_OUTPUT="$PLATFORM_OUT_DIR/$ARTIFACT_NAME"
if [[ "$(absolute_path "$ARTIFACT_PATH")" != "$(absolute_path "$ARTIFACT_OUTPUT")" ]]; then
    cp -p "$ARTIFACT_PATH" "$ARTIFACT_OUTPUT"
fi

SYMBOLS_FILE="$PLATFORM_OUT_DIR/lite-backend-symbols.txt"
RAW_SYMBOLS_FILE="$PLATFORM_OUT_DIR/lite-backend-symbols.raw.txt"
NM_TOOL="$(select_nm_tool)"

info "capturing exported symbols with $NM_TOOL"
if ! "$NM_TOOL" -g --defined-only "$ARTIFACT_OUTPUT" > "$RAW_SYMBOLS_FILE" 2> "$PLATFORM_OUT_DIR/lite-backend-symbols.err.txt"; then
    die "symbol inventory failed; see $PLATFORM_OUT_DIR/lite-backend-symbols.err.txt"
fi
awk '{print $NF}' "$RAW_SYMBOLS_FILE" \
    | sed 's/^_//' \
    | grep -E '^(litelib_[A-Za-z0-9_]*|blake3_PW)$' \
    | sort -u > "$SYMBOLS_FILE" || true

[[ -s "$SYMBOLS_FILE" ]] || die "no SDXL C ABI symbols were found in $ARTIFACT_OUTPUT"

MISSING_SYMBOLS=()
for required in "${REQUIRED_SYMBOLS[@]}"; do
    if ! grep -Fxq "$required" "$SYMBOLS_FILE"; then
        MISSING_SYMBOLS+=("$required")
    fi
done
if [[ ${#MISSING_SYMBOLS[@]} -ne 0 ]]; then
    printf '%s\n' "${MISSING_SYMBOLS[@]}" > "$PLATFORM_OUT_DIR/lite-backend-missing-symbols.txt"
    die "artifact is missing required symbols; see $PLATFORM_OUT_DIR/lite-backend-missing-symbols.txt"
fi

SHA256_DIGEST="$(compute_sha256 "$ARTIFACT_OUTPUT")"
validate_signature_metadata
ARTIFACT_SIZE_BYTES="$(wc -c < "$ARTIFACT_OUTPUT" | tr -d ' ')"
PROJECT_REVISION="$(source_revision_for "$PROJECT_ROOT")"
BACKEND_REVISION="$(source_revision_for "$BACKEND_SOURCE_DIR")"
BACKEND_DEPENDENCY_REVISION=""
if [[ -n "$BACKEND_DEPENDENCY_DIR" ]]; then
    BACKEND_DEPENDENCY_REVISION="$(source_revision_for "$BACKEND_DEPENDENCY_DIR")"
fi
ARTIFACT_SET_ID="$PLATFORM-${SHA256_DIGEST:0:16}"
REPRODUCIBLE_MANIFEST_VALUE=false
if [[ "$BUILD_ARTIFACT" == true && "$REPRODUCIBLE" == true ]]; then
    REPRODUCIBLE_MANIFEST_VALUE=true
fi
PORTABLE_DEPENDENCY_OVERRIDE_MANIFEST_VALUE=false
if [[ "$BACKEND_DEPENDENCY_OVERRIDE_REQUESTED" == true ]]; then
    PORTABLE_DEPENDENCY_OVERRIDE_MANIFEST_VALUE=true
fi
FILE_DESCRIPTION="unknown"
if command -v file >/dev/null 2>&1; then
    FILE_DESCRIPTION="$(file -b "$ARTIFACT_OUTPUT")"
fi

MANIFEST_FILE="$PLATFORM_OUT_DIR/lite-backend-artifact-manifest.json"
{
    printf '{\n'
    printf '  "schema": "dragonx.lite.backend-artifact.v1",\n'
    printf '  "generated_by": "scripts/build-lite-backend-artifact.sh",\n'
    printf '  "read_only_inventory": true,\n'
    printf '  "artifact_mutation_requested": false,\n'
    printf '  "upload_requested": false,\n'
    printf '  "signing_requested": false,\n'
    printf '  "publication_requested": false,\n'
    printf '  "signature_verification": {\n'
    printf '    "policy_name": '; json_escape "$SIGNATURE_POLICY_NAME"; printf ',\n'
    printf '    "policy_defined": %s,\n' "$SIGNATURE_POLICY_DEFINED_MANIFEST_VALUE"
    printf '    "required_for_release": %s,\n' "$SIGNATURE_REQUIRED_MANIFEST_VALUE"
    printf '    "metadata_read_only": true,\n'
    printf '    "metadata_provided": %s,\n' "$SIGNATURE_METADATA_PROVIDED"
    printf '    "verification_performed": %s,\n' "$SIGNATURE_VERIFICATION_PERFORMED"
    printf '    "verification_status": '; json_escape "$SIGNATURE_VERIFICATION_STATUS"; printf ',\n'
    printf '    "signature_format": '; json_escape "$SIGNATURE_FORMAT"; printf ',\n'
    printf '    "signature_path": '; json_escape "$SIGNATURE_FILE"; printf ',\n'
    printf '    "signature_file_sha256": '; json_escape "$SIGNATURE_FILE_SHA256"; printf ',\n'
    printf '    "verification_tool": '; json_escape "$SIGNATURE_VERIFICATION_TOOL"; printf ',\n'
    printf '    "verification_command": '; json_escape "$SIGNATURE_VERIFICATION_COMMAND"; printf ',\n'
    printf '    "key_fingerprint": '; json_escape "$SIGNATURE_KEY_FINGERPRINT"; printf ',\n'
    printf '    "certificate_identity": '; json_escape "$SIGNATURE_CERTIFICATE_IDENTITY"; printf ',\n'
    printf '    "certificate_issuer": '; json_escape "$SIGNATURE_CERTIFICATE_ISSUER"; printf ',\n'
    printf '    "transparency_log_url": '; json_escape "$SIGNATURE_TRANSPARENCY_LOG_URL"; printf ',\n'
    printf '    "verified_artifact_sha256": '; json_escape "$SIGNATURE_VERIFIED_SHA256"; printf '\n'
    printf '  },\n'
    printf '  "abi_version": '; json_escape "$ABI_VERSION"; printf ',\n'
    printf '  "link_mode": '; json_escape "$LINK_MODE"; printf ',\n'
    printf '  "platform": '; json_escape "$PLATFORM"; printf ',\n'
    printf '  "rust_target": '; json_escape "$RUST_TARGET"; printf ',\n'
    printf '  "artifact": {\n'
    printf '    "path": '; json_escape "$ARTIFACT_OUTPUT"; printf ',\n'
    printf '    "kind": '; json_escape "$KIND"; printf ',\n'
    printf '    "size_bytes": %s,\n' "$ARTIFACT_SIZE_BYTES"
    printf '    "sha256": '; json_escape "$SHA256_DIGEST"; printf ',\n'
    printf '    "file_description": '; json_escape "$FILE_DESCRIPTION"; printf '\n'
    printf '  },\n'
    printf '  "symbol_inventory": {\n'
    printf '    "tool": '; json_escape "$NM_TOOL"; printf ',\n'
    printf '    "symbols_path": '; json_escape "$SYMBOLS_FILE"; printf ',\n'
    printf '    "raw_symbols_path": '; json_escape "$RAW_SYMBOLS_FILE"; printf ',\n'
    printf '    "required_symbols": '; json_array "${REQUIRED_SYMBOLS[@]}"; printf ',\n'
    printf '    "exported_symbols": '; json_array_from_file "$SYMBOLS_FILE"; printf ',\n'
    printf '    "missing_required_symbols": []\n'
    printf '  },\n'
    printf '  "provenance": {\n'
    printf '    "owner_ready": true,\n'
    printf '    "built_from_source": true,\n'
    printf '    "metadata_provided": true,\n'
    printf '    "source": '; json_escape "$BACKEND_SOURCE_DIR"; printf ',\n'
    printf '    "cargo_build_source": '; json_escape "$BUILD_BACKEND_DIR"; printf ',\n'
    printf '    "portable_dependency_override": %s,\n' "$PORTABLE_DEPENDENCY_OVERRIDE_MANIFEST_VALUE"
    printf '    "silentdragonxlitelib_source": '; json_escape "$BACKEND_DEPENDENCY_DIR"; printf ',\n'
    printf '    "builder": '; json_escape "$BUILDER"; printf ',\n'
    printf '    "source_revision": '; json_escape "$BACKEND_REVISION"; printf ',\n'
    printf '    "silentdragonxlitelib_revision": '; json_escape "$BACKEND_DEPENDENCY_REVISION"; printf ',\n'
    printf '    "project_revision": '; json_escape "$PROJECT_REVISION"; printf ',\n'
    printf '    "artifact_set_id": '; json_escape "$ARTIFACT_SET_ID"; printf ',\n'
    printf '    "source_date_epoch": '; json_escape "$SOURCE_DATE_EPOCH_VALUE"; printf ',\n'
    printf '    "reproducible": %s,\n' "$REPRODUCIBLE_MANIFEST_VALUE"
    printf '    "redacted": true\n'
    printf '  }\n'
    printf '}\n'
} > "$MANIFEST_FILE"

info "artifact: $ARTIFACT_OUTPUT"
info "symbols:  $SYMBOLS_FILE"
info "manifest: $MANIFEST_FILE"
info "sha256:   $SHA256_DIGEST"
cat <<EOF

CMake configure example:
cmake -S "$PROJECT_ROOT" -B "$PROJECT_ROOT/build/lite" \\
  -DDRAGONX_BUILD_LITE=ON \\
  -DDRAGONX_ENABLE_LITE_BACKEND=ON \\
  -DDRAGONX_LITE_BACKEND_LIBRARY="$ARTIFACT_OUTPUT" \\
  -DDRAGONX_LITE_BACKEND_SYMBOLS_FILE="$SYMBOLS_FILE" \\
  -DDRAGONX_LITE_BACKEND_MANIFEST="$MANIFEST_FILE" \\
  -DDRAGONX_LITE_BACKEND_LINK_MODE=$LINK_MODE \\
  -DDRAGONX_LITE_BACKEND_ABI=$ABI_VERSION
EOF