#!/usr/bin/perl

use strict;
#use warnings;

my @formulas = qw(libpng zstd libzip portaudio libogg flac libvorbis opus libsndfile libsamplerate libxml2); ### DO NOT CHANGE ORDER ###
my @libs = qw(libFLAC.dylib libogg.dylib libopus.dylib libpng16.dylib libportaudio.dylib libsamplerate.dylib libsndfile.dylib libvorbis.dylib libvorbisenc.dylib libxml2.dylib libzip.dylib libzstd.dylib);

if($0 !~ m/\.\/build_openemulator|\.\/build_openemulator-standalone|\.\/build_openemulator-universal/) {
    die "bad!"
}

my @archs = qw(x86_64 arm64);
my ($native_arch, $foreign_arch) = @archs;
if(`uname -m` !~ m/x86_64/) {
    $native_arch = $archs[1];
    $foreign_arch = @archs[0];
}

my $lib_prefix = "/usr/local";
if($native_arch eq $archs[1]) {
    $lib_prefix = "/opt/homebrew";
}

# Check brew installed, up-to-date and required libraries are installed
print "Checking current brew installation...\n";
system("which brew >/dev/null") == 0 or die "error: could not run brew: $?\n";
#system("HOMEBREW_NO_ENV_HINTS=1 brew update") == 0 or die "error: could not update brew: $?\n";
#system("HOMEBREW_NO_ENV_HINTS=1 brew upgrade") == 0 or die "error: could not upgrade brew: $?\n";
system("HOMEBREW_NO_ENV_HINTS=1 brew install cmake") == 0 or die "error: could not install cmake: $?\n";
foreach my $formula (@formulas) {
    system("HOMEBREW_NO_ENV_HINTS=1 brew install $formula") == 0 or die "error: could not install $formula: $?\n";
}

if($0 ne "./build_openemulator") {
    system("mkdir -p ./lib") == 0 or die "error: could not create ./lib directory: $?\n";
}

if($0 eq "./build_openemulator-standalone") {
    # Copying libraries to ./lib
    print "\nCopying $native_arch libraries to ./lib directory...\n";
    foreach my $lib (@libs) {
        if($lib eq "libxml2.dylib") {
            system("cp $lib_prefix/opt/libxml2/lib/$lib ./lib/") == 0 or die "error: could not copy library [$lib]: $?\n";
        } else {
            system("cp $lib_prefix/lib/$lib ./lib/") == 0 or die "error: could not copy library [$lib]: $?\n";
        }
    }
}

if($0 eq "./build_openemulator-universal") {
    # Install foreign arch libraries
    print "\nInstalling $foreign_arch libraries...\n";
    foreach my $formula (@formulas) {
        print "\ndownloading [$formula]...\n";
        my $response = `brew fetch --force --bottle-tag=${foreign_arch}_big_sur $formula`;
        if($response =~ m/Downloaded to: (.*?)\s+/s) {
            print "installing...\n";
            system("tar", "-xvzf", $1, "--strip-components=2", "-C", "./", "*/*/lib") == 0 or die "error: could not extract archive [$response]: $?\n";
            system("rm $1");
        }
    }

    fixLibPaths();

    # Create universal libraries
    print "\nCreating universal libraries...\n";
    foreach my $lib (@libs) {
        print "creating [$lib]...\n";
        if($lib eq "libxml2.dylib") {
            system("lipo -create $lib_prefix/opt/libxml2/lib/$lib ./lib/$lib -output ./lib/$lib") == 0 or die "error: could not create universal library for $lib: $?\n";
        } else {
            system("lipo -create $lib_prefix/lib/$lib ./lib/$lib -output ./lib/$lib") == 0 or die "error: could not create universal library for $lib: $?\n";
        }
    }
}

if($0 ne "./build_openemulator") {
    fixLibPaths();
}

print "\nBuilding libemulation...\n";
if($0 eq "./build_openemulator") {
    system("cmake -Hmodules/libemulation -Bmodules/libemulation/build -DCMAKE_BUILD_TYPE=Release") == 0 or die "error: could not run [cmake]: $?\n";
} elsif($0 eq "./build_openemulator-standalone") {
    system("CMAKE_PREFIX_PATH=./lib cmake -Hmodules/libemulation -Bmodules/libemulation/build -DCMAKE_BUILD_TYPE=Release") == 0 or die "error: could not run [cmake]: $?\n";
} else {
    system("UNIVERSAL=1 CMAKE_PREFIX_PATH=./lib cmake -Hmodules/libemulation -Bmodules/libemulation/build -DCMAKE_BUILD_TYPE=Release") == 0 or die "error: could not run [cmake]: $?\n";
}
system("cmake --build modules/libemulation/build --config Release") == 0 or die "error: could not run [cmake]: $?\n";

print "\nBuilding OpenEmulator...\n";
if($0 eq "./build_openemulator") {
    system("xcodebuild -arch $native_arch") == 0 or die "error: could not run [xcodebuild]: $?\n";
} elsif($0 eq "./build_openemulator-standalone") {
    system("xcodebuild -arch $native_arch -target OpenEmulator-standalone") == 0 or die "error: could not run [xcodebuild]: $?\n";
} else {
    system("xcodebuild -arch $native_arch -arch $foreign_arch -target OpenEmulator-standalone") == 0 or die "error: could not run [xcodebuild]: $?\n";
}


sub fixLibPaths {
    # Adjust library IDs and load paths
    print "\nChanging library install names...\n";
    my %libname;
    LIB: foreach my $lib (@libs) {
        foreach my $l (`otool -L ./lib/$lib`) {
            if(my $path = ($l =~ /^\s+(.*?)\s/)[0]) {
                my $name = ($path =~ /.*\/(.*?)$/)[0];
                $libname{$name} = $lib;
                next LIB;
            }
        }
    }

    foreach my $lib (@libs) {
        system("install_name_tool -id \@executable_path/../Frameworks/$lib ./lib/$lib 2>/dev/null");
        foreach my $l (`otool -L ./lib/$lib`) {
            if(my $path = ($l =~ /^\s+((\@\@HOMEBREW.*?|$lib_prefix)\/.*?)\s/)[0]) {
                my $name = ($path =~ /.*\/(.*?)$/)[0];
                system("install_name_tool -change $path \@executable_path/../Frameworks/" . $libname{$name} . " ./lib/$lib 2>/dev/null");
            }
        }
    }
}
