#!/bin/sh
set -eu

script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
repo_dir=$(dirname "$script_dir")
source_dir=${MOUSE_SOURCE_DIR:-"$repo_dir/sources"}
build_dir=${MOUSE_BUILD_DIR:-"$repo_dir/build"}
static_dir="$build_dir/static"
source_build_dir="$static_dir/src"
sysroot="$static_dir/sysroot"
base_root="$static_dir/rootfs"
tools_dir="$static_dir/tools"
jobs=${MOUSE_BUILD_JOBS:-$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || printf '2')}

case "$static_dir" in
    "$repo_dir"/build/static) ;;
    *)
        printf '%s\n' "refusing to clear unexpected static build path: $static_dir" >&2
        exit 1
        ;;
esac

target_libdir=$(rustc --print target-libdir --target x86_64-unknown-linux-musl)
builtins=$(find "$target_libdir" -maxdepth 1 -name 'libcompiler_builtins-*.rlib' -print | head -1)

case "$(uname -s)" in
    Linux)
        lld=$(command -v ld.lld)
        llvm_ar=$(command -v llvm-ar)
        llvm_strip=$(command -v llvm-strip)
        build_triplet=$(cc -dumpmachine)
        native_cc=cc
        ;;
    Darwin)
        rust_sysroot=$(rustc --print sysroot)
        rust_toolchains_dir=$(dirname "$rust_sysroot")
        lld="$rust_sysroot/lib/rustlib/aarch64-apple-darwin/bin/gcc-ld/ld.lld"
        llvm_ar=$(find "$rust_toolchains_dir" -path '*/lib/rustlib/aarch64-apple-darwin/bin/llvm-ar' -print | head -1)
        llvm_strip=$(find "$rust_toolchains_dir" -path '*/lib/rustlib/aarch64-apple-darwin/bin/llvm-strip' -print | head -1)
        build_triplet=aarch64-apple-darwin
        native_cc=clang
        ;;
    *)
        printf '%s\n' "unsupported build host: $(uname -s)" >&2
        exit 1
        ;;
esac

for requirement in "$lld" "$builtins" "$llvm_ar" "$llvm_strip"; do
    if [ ! -f "$requirement" ]; then
        printf '%s\n' "missing LLVM/Rust cross-build component: $requirement" >&2
        exit 1
    fi
done

rm -rf "$static_dir"
install -d -m 0755 "$source_build_dir" "$sysroot" "$base_root/usr/bin" "$tools_dir/bin"

extract() {
    tar -xf "$source_dir/$1" -C "$source_build_dir"
}

extract meson-1.9.1.tar.gz
extract ninja-1.13.1.tar.gz
extract pkgconf-2.5.1.tar.gz
extract musl-1.2.6.tar.gz
extract netbsd-curses-0.3.2.tar.gz
extract attr-2.5.2.tar.gz
extract acl-2.3.2.tar.gz
extract libxo-1.7.5.tar.gz
extract tcsh-6.24.16.tar.gz
extract chimerautils-15.0.3.tar.gz
extract libcap-2.77.tar.xz
extract openrc-0.63.3.tar.gz

patch -d "$source_build_dir/tcsh-TCSH6_24_16" -p1 \
    <"$repo_dir/patches/tcsh-gethost-native.patch"
patch -d "$source_build_dir/chimerautils-15.0.3" -p1 \
    <"$repo_dir/patches/chimerautils-native-cdefs.patch"
patch -d "$source_build_dir/openrc-0.63.3" -p1 \
    <"$repo_dir/patches/openrc-mouse-tool-surface.patch"

(
    cd "$source_build_dir/ninja-1.13.1"
    python3 configure.py --bootstrap
    install -m 0755 ninja "$tools_dir/bin/ninja"
)

meson_source="$source_build_dir/meson-1.9.1/meson.py"
PATH="$tools_dir/bin:$PATH"
export PATH

python3 "$meson_source" setup \
    "$source_build_dir/pkgconf-pkgconf-2.5.1/build" \
    "$source_build_dir/pkgconf-pkgconf-2.5.1" \
    --prefix="$tools_dir" \
    --buildtype=release \
    --default-library=static
python3 "$meson_source" compile -C "$source_build_dir/pkgconf-pkgconf-2.5.1/build"
python3 "$meson_source" install -C "$source_build_dir/pkgconf-pkgconf-2.5.1/build"

musl_cc="clang --target=x86_64-unknown-linux-musl --ld-path=$lld"
MOUSE_LLVM_AR="$llvm_ar"
export MOUSE_LLVM_AR
(
    cd "$source_build_dir/musl-1.2.6"
    CC="$musl_cc" \
        AR="$llvm_ar" \
        RANLIB="$script_dir/mouse-ranlib" \
        ./configure \
        --target=x86_64 \
        --prefix=/usr \
        --syslibdir=/lib \
        --disable-shared
    make -s -j"$jobs"
    make -s DESTDIR="$sysroot" install
)

install -d -m 0755 "$sysroot/usr/include/sys"
install -m 0644 "$source_dir/cdefs.h" "$sysroot/usr/include/sys/cdefs.h"
install -m 0644 "$source_dir/queue.h" "$sysroot/usr/include/sys/queue.h"
install -m 0644 "$source_dir/tree.h" "$sysroot/usr/include/sys/tree.h"
install -m 0644 "$source_dir/error.h" "$sysroot/usr/include/error.h"

MOUSE_SYSROOT="$sysroot"
MOUSE_LLD="$lld"
MOUSE_BUILTINS="$builtins"
MOUSE_LINK_COMPAT="$static_dir/static-link-compat.o"
MOUSE_LLVM_AR="$llvm_ar"
clang \
    --target=x86_64-unknown-linux-musl \
    --sysroot="$sysroot" \
    -c "$repo_dir/support/static-link-compat.c" \
    -o "$MOUSE_LINK_COMPAT"
export MOUSE_SYSROOT MOUSE_LLD MOUSE_BUILTINS MOUSE_LINK_COMPAT MOUSE_LLVM_AR

cc="$script_dir/mouse-cc"
cxx="$script_dir/mouse-cxx"
ranlib="$script_dir/mouse-ranlib"

(
    cd "$source_build_dir/netbsd-curses-0.3.2"
    make -s -f GNUmakefile -j"$jobs" \
        CC="$cc" \
        HOSTCC="$native_cc" \
        AR="$llvm_ar" \
        RANLIB="$ranlib" \
        CFLAGS="-O2" \
        CPPFLAGS="-I. -I./libterminfo -DTERMINFO_COMPILE -DTERMINFO_DB -DTERMINFO_COMPAT" \
        LDFLAGS="-static" \
        PREFIX=/usr \
        all-static
    make -s -f GNUmakefile \
        CC="$cc" \
        HOSTCC="$native_cc" \
        AR="$llvm_ar" \
        RANLIB="$ranlib" \
        CFLAGS="-O2" \
        CPPFLAGS="-I. -I./libterminfo -DTERMINFO_COMPILE -DTERMINFO_DB -DTERMINFO_COMPAT" \
        LDFLAGS="-static" \
        PREFIX=/usr \
        DESTDIR="$sysroot" \
        install-static
)

build_autoconf_library() {
    source_name=$1
    build_target=$2
    shift 2
    (
        cd "$source_build_dir/$source_name"
        CC="$cc" \
            AR="$llvm_ar" \
            RANLIB="$ranlib" \
            PKG_CONFIG="$tools_dir/bin/pkgconf" \
            PKG_CONFIG_LIBDIR="$sysroot/usr/lib/pkgconfig" \
            PKG_CONFIG_SYSROOT_DIR="$sysroot" \
            ./configure \
            --build="$build_triplet" \
            --host=x86_64-linux-musl \
            --prefix=/usr \
            --disable-shared \
            --enable-static \
            "$@"
        make -s -j"$jobs" "$build_target"
        make -s DESTDIR="$sysroot" \
            install-libLTLIBRARIES \
            install-data-local \
            install-pkgconfDATA
    )
}

build_autoconf_library attr-2.5.2 libattr.la
build_autoconf_library acl-2.3.2 libacl.la

# The projects' install-time EXPORT substitution uses a GNU sed word-boundary
# extension which macOS sed accepts but does not apply. Normalize the installed
# public declarations for consumers of the cross-built static libraries.
find "$sysroot/usr/include/attr" "$sysroot/usr/include/acl" \
    "$sysroot/usr/include/sys/acl.h" \
    -type f -exec perl -pi -e 's/\bEXPORT\b/extern/g' {} +

(
    cd "$source_build_dir/libxo-1.7.5"
    CC="$cc" \
        AR="$llvm_ar" \
        RANLIB="$ranlib" \
        ac_cv_func_malloc_0_nonnull=yes \
        ac_cv_func_realloc_0_nonnull=yes \
        ./configure \
        --build="$build_triplet" \
        --host=x86_64-linux-musl \
        --prefix=/usr \
        --disable-shared \
        --enable-static \
        --disable-libxo-options \
        --disable-gettext \
        --enable-text-only
    make -s -C libxo -j"$jobs" libxo.la
    make -s -C libxo DESTDIR="$sysroot" \
        install-libLTLIBRARIES \
        install-libxoincHEADERS
    make -s DESTDIR="$sysroot" install-pkgconfigDATA
)

(
    cd "$source_build_dir/tcsh-TCSH6_24_16"
    CC="$cc" \
        LIBS="-lcurses -lterminfo" \
        ./configure \
        --build="$build_triplet" \
        --host=x86_64-linux-musl \
        --prefix=/usr \
        --disable-nls-catalogs
    make -j"$jobs"
    install -m 0755 tcsh "$base_root/usr/bin/tcsh"
)

cross_file="$static_dir/chimerautils.cross"
{
    printf '%s\n' \
        '[binaries]' \
        "c = '$cc'" \
        "cpp = '$cxx'" \
        "ar = '$llvm_ar'" \
        "strip = '$llvm_strip'" \
        "pkg-config = '$tools_dir/bin/pkgconf'" \
        '' \
        '[host_machine]' \
        "system = 'linux'" \
        "cpu_family = 'x86_64'" \
        "cpu = 'x86_64'" \
        "endian = 'little'" \
        '' \
        '[built-in options]' \
        "c_args = ['-O2']" \
        "cpp_args = ['-O2']" \
        "c_link_args = ['-static']" \
        "cpp_link_args = ['-static']" \
        "default_library = 'static'" \
        "prefer_static = true"
} >"$cross_file"

(
    cd "$source_build_dir/libcap-2.77"
    make -s -C libcap -j"$jobs" \
        CC="$cc" \
        BUILD_CC="$native_cc" \
        AR="$llvm_ar" \
        RANLIB="$ranlib" \
        SHARED=no \
        PTHREADS=no \
        USE_GPERF=no \
        GOLANG=no \
        PAM_CAP=no \
        libcap.a
    install -d -m 0755 \
        "$sysroot/usr/include/linux" \
        "$sysroot/usr/include/sys" \
        "$sysroot/usr/lib/pkgconfig"
    install -m 0644 libcap/libcap.a "$sysroot/usr/lib/libcap.a"
    install -m 0644 \
        libcap/include/sys/capability.h \
        "$sysroot/usr/include/sys/capability.h"
    install -m 0644 \
        libcap/include/uapi/linux/capability.h \
        "$sysroot/usr/include/linux/capability.h"
    sed \
        -e 's,@prefix@,/usr,' \
        -e 's,@exec_prefix@,/usr,' \
        -e 's,@libdir@,/usr/lib,' \
        -e 's,@includedir@,/usr/include,' \
        -e 's,@VERSION@,2.77,' \
        -e 's,@deps@,,' \
        libcap/libcap.pc.in >"$sysroot/usr/lib/pkgconfig/libcap.pc"
)

openrc_build="$source_build_dir/openrc-0.63.3/build"
openrc_install="$static_dir/openrc-install"
PKG_CONFIG_LIBDIR="$sysroot/usr/lib/pkgconfig:$sysroot/usr/share/pkgconfig" \
PKG_CONFIG_SYSROOT_DIR="$sysroot" \
    python3 "$meson_source" setup \
    "$openrc_build" \
    "$source_build_dir/openrc-0.63.3" \
    --cross-file="$cross_file" \
    --prefix=/usr \
    --bindir=bin \
    --sbindir=bin \
    --libdir=lib \
    --libexecdir=lib \
    --sysconfdir=/etc \
    --buildtype=release \
    -Daudit=disabled \
    -Dbash-completions=false \
    -Dnewnet=false \
    -Dpam=false \
    -Dpkgconfig=false \
    -Dselinux=disabled \
    -Dsysvinit=false \
    -Dzsh-completions=false
PKG_CONFIG_LIBDIR="$sysroot/usr/lib/pkgconfig:$sysroot/usr/share/pkgconfig" \
PKG_CONFIG_SYSROOT_DIR="$sysroot" \
    python3 "$meson_source" compile -C "$openrc_build"
DESTDIR="$openrc_install" \
    python3 "$meson_source" install -C "$openrc_build"

for command in \
    openrc openrc-run rc-service rc-sstat rc-status \
    start-stop-daemon supervise-daemon
do
    install -m 0755 \
        "$openrc_install/usr/bin/$command" \
        "$base_root/usr/bin/$command"
done
ln -s openrc-run "$base_root/usr/bin/runscript"
ln -s rc-service "$base_root/usr/bin/service"

install -d -m 0755 "$base_root/usr/lib"
cp -R "$openrc_install/usr/lib/rc" "$base_root/usr/lib/"
install -d -m 0755 "$base_root/etc/init.d"
cp -P "$openrc_install/etc/init.d/functions.sh" "$base_root/etc/init.d/functions.sh"

install -d -m 0755 "$base_root/usr/lib/mouse/manifests"
{
    printf '%s\n' \
        /etc/init.d/functions.sh \
        /usr/bin/openrc \
        /usr/bin/openrc-run \
        /usr/bin/rc-service \
        /usr/bin/rc-sstat \
        /usr/bin/rc-status \
        /usr/bin/runscript \
        /usr/bin/service \
        /usr/bin/start-stop-daemon \
        /usr/bin/supervise-daemon
    find "$base_root/usr/lib/rc" -type f -o -type l |
        sed "s|^$base_root||"
} | LC_ALL=C sort >"$base_root/usr/lib/mouse/manifests/openrc.files"

chimerautils_build="$source_build_dir/chimerautils-15.0.3/build"
PKG_CONFIG_LIBDIR="$sysroot/usr/lib/pkgconfig:$sysroot/usr/share/pkgconfig" \
PKG_CONFIG_SYSROOT_DIR="$sysroot" \
    python3 "$meson_source" setup \
    "$chimerautils_build" \
    "$source_build_dir/chimerautils-15.0.3" \
    --cross-file="$cross_file" \
    --prefix=/usr \
    --buildtype=release \
    -Dopenssl=disabled \
    -Dlibedit=disabled \
    -Dzlib=disabled \
    -Dlzma=disabled \
    -Dbzip2=disabled \
    -Dzstd=disabled \
    -Dpam=disabled \
    -Dselinux=disabled \
    -Dchimera_realpath=disabled

commands="
cat chmod chown cksum cp date dd df echo env find grep head hostname id kill
ls mkdir mv pwd realpath rm rmdir sed sh sleep stat stty sync tail touch
tty uname wc
"

targets="
src.freebsd/coreutils/cat/cat
src.freebsd/coreutils/chmod/chmod
src.freebsd/coreutils/chown/chown
src.freebsd/coreutils/cksum/cksum
src.freebsd/coreutils/cp/cp
src.freebsd/coreutils/date/date
src.freebsd/coreutils/dd/dd
src.freebsd/coreutils/df/df
src.freebsd/coreutils/echo/echo
src.freebsd/coreutils/env/env
src.freebsd/findutils/find/find
src.freebsd/grep/grep
src.freebsd/coreutils/head/head
src.freebsd/coreutils/hostname/hostname
src.freebsd/coreutils/id/id
src.freebsd/miscutils/kill/kill
src.freebsd/coreutils/ls/ls
src.freebsd/coreutils/mkdir/mkdir
src.freebsd/coreutils/mv/mv
src.freebsd/coreutils/pwd/pwd
src.freebsd/coreutils/realpath/realpath
src.freebsd/coreutils/rm/rm
src.freebsd/coreutils/rmdir/rmdir
src.freebsd/sed/sed
src.freebsd/sh/sh
src.freebsd/coreutils/sleep/sleep
src.freebsd/coreutils/stat/stat
src.freebsd/coreutils/stty/stty
src.freebsd/coreutils/sync/sync
src.freebsd/coreutils/tail/tail
src.freebsd/coreutils/touch/touch
src.freebsd/coreutils/tty/tty
src.freebsd/coreutils/uname/uname
src.freebsd/coreutils/wc/wc
"

PKG_CONFIG_LIBDIR="$sysroot/usr/lib/pkgconfig:$sysroot/usr/share/pkgconfig" \
PKG_CONFIG_SYSROOT_DIR="$sysroot" \
    python3 "$meson_source" compile -C "$chimerautils_build" $targets

for command in $commands; do
    binary=$(find "$chimerautils_build" -type f -name "$command" -perm -0100 -print | head -1)
    if [ -z "$binary" ]; then
        printf '%s\n' "missing ChimeraUtils build output: $command" >&2
        exit 1
    fi
    install -m 0755 "$binary" "$base_root/usr/bin/$command"
done

# ChimeraUtils installs whoami as an argv[0]-sensitive alias of id. A separate
# copy keeps the initramfs self-contained without requiring a symlink utility
# during image assembly.
install -m 0755 "$base_root/usr/bin/id" "$base_root/usr/bin/whoami"

install -m 0755 "$sysroot/usr/bin/tput" "$base_root/usr/bin/tput"
ln -s tcsh "$base_root/usr/bin/csh"

printf '%s\n' '#!/bin/sh' 'exec /usr/bin/tput clear' >"$base_root/usr/bin/clear"
chmod 0755 "$base_root/usr/bin/clear"

"$script_dir/audit-static-base.sh" "$base_root"
printf '%s\n' "$base_root"
