use alienfile;
use Config;

# The corvus-json-schema C library (src-rs/corvus-json-schema-capi), version 0.1.6 or later in the 0.1 series.
#
# An installed library that pkg-config finds as corvus-json-schema is used as it is (the "system" install, linked
# dynamically). Otherwise the release package for this platform is downloaded from the C library's GitHub release,
# checked against the SHA-256 digest recorded here, and installed into this distribution's share directory (the
# "share" install). There the static library is linked, so JSON::Schema::Corvus::XS has nothing to find at run time,
# except on Windows, where the C library is a DLL that Alien::CorvusJsonSchema->dynamic_libs names.

my $version = '0.1.6';

my %digest = (
  'aarch64-pc-windows-msvc'    => 'd2d1c23420207d4ef47447c79e6dc25ca9f5d24ab278d7ce2eec7606812e2adc',
  'aarch64-unknown-linux-gnu'  => 'bb7c59e794313c9451846d04d2212c5bc90aa4abaf058fe204677180d3ce1a3c',
  'aarch64-unknown-linux-musl' => '91b6fb9b7062070ba03a6dd5a72bbed6951ea7d39053efe54818bc07b777e597',
  'universal2-apple-darwin'    => 'fbf5998a94e040011cd700fe36eaa11aab8fc20d76975f627c42210b281b0d7b',
  'x86_64-pc-windows-msvc'     => '4da0256e4ab7787599e115b617424348b712be36a532270d3c48497954f89d07',
  'x86_64-unknown-linux-gnu'   => '9e21919abd1a49b3a664e216fd6ef5cbd496b8fcfa9a8d4bc702975dffad2c5c',
  'x86_64-unknown-linux-musl'  => 'b328df93e37a36e52cea09fb790a3445cbbc40d881860b251fa645c0376b421d',
);

# The release package's target for this Perl, or undef when the release has none.
sub target {
  my $arch = $Config{archname};
  my $cpu = $arch =~ /^(?:x86_64|amd64|x64)/i || $arch =~ /-x64-/i ? 'x86_64'
          : $arch =~ /^(?:aarch64|arm64)/i || $arch =~ /-arm64-/i ? 'aarch64'
          : undef;
  return 'universal2-apple-darwin' if $^O eq 'darwin';
  return undef unless defined $cpu;
  return "$cpu-unknown-linux-" . ($Config{gnulibc_version} ? 'gnu' : 'musl') if $^O eq 'linux';
  return "$cpu-pc-windows-msvc" if $^O eq 'MSWin32';
  return undef;
}

configure {
  requires 'Alien::Build::Plugin::Digest::SHA' => 0;
};

plugin 'PkgConfig' => (
  pkg_name        => 'corvus-json-schema',
  minimum_version => $version,
);

share {
  my $target = target();
  unless (defined $target) {
    die "There is no release package of the corvus-json-schema C library for $^O ($Config{archname}). Build it from "
      . "src-rs/corvus-json-schema-capi (https://github.com/corvus-dotnet/Corvus.JsonSchema), install it where "
      . "pkg-config finds corvus-json-schema.pc, and install this distribution again.\n";
  }
  if ($^O eq 'MSWin32' && $Config{cc} !~ /gcc/i) {
    die "On Windows this distribution needs a Perl built with gcc (Strawberry Perl), which links the C library's DLL. "
      . "Install the C library where pkg-config finds it instead.\n";
  }
  my $extension = $^O eq 'MSWin32' ? 'zip' : 'tar.gz';
  my $name = "corvus-json-schema-$version-$target";

  start_url "https://github.com/corvus-dotnet/Corvus.JsonSchema/releases/download/capi-v$version/$name.$extension";
  plugin 'Download';
  plugin 'Digest' => [ SHA256 => $digest{$target} ];
  plugin 'Extract' => $extension;

  # The package is prebuilt: installing it is copying it. Only the static library is kept on Linux and macOS, so that
  # -lcorvus_json_schema links it rather than the shared one. On Windows the DLL is kept, with an import library
  # under the name gcc's linker looks for.
  build sub {
    my ($build) = @_;
    require File::Copy;
    require File::Path;
    my $prefix = $build->install_prop->{stage};
    File::Path::mkpath([ "$prefix/include", "$prefix/lib" ]);
    for my $file (qw(corvus_json_schema.h corvus_json_schema.hpp)) {
      File::Copy::copy("include/$file", "$prefix/include/$file") or die "copy include/$file: $!";
    }
    for my $file (qw(LICENSE THIRD-PARTY-NOTICES.txt)) {
      File::Copy::copy($file, "$prefix/$file") or die "copy $file: $!";
    }
    if ($^O eq 'MSWin32') {
      File::Path::mkpath(["$prefix/bin"]);
      File::Copy::copy('bin/corvus_json_schema.dll', "$prefix/bin/corvus_json_schema.dll") or die "copy the DLL: $!";
      File::Copy::copy('lib/corvus_json_schema.dll.lib', "$prefix/lib/libcorvus_json_schema.dll.a")
        or die "copy the import library: $!";
    }
    else {
      File::Copy::copy('lib/libcorvus_json_schema.a', "$prefix/lib/libcorvus_json_schema.a")
        or die "copy the static library: $!";
    }
  };

  # The PkgConfig plugin registers a gather hook for share installs too, which would read a .pc file from the staged
  # package. This package has none (the release's names the shared library, and the share install links the static
  # one), so the share install's properties are set here instead, and that hook is not run.
  meta->around_hook(gather_share => sub {
    my (undef, $build) = @_;
    my $prefix = $build->runtime_prop->{prefix};
    my $private = $^O eq 'linux'
      ? ($target =~ /musl$/ ? '-lgcc_s -lc' : '-lgcc_s -lutil -lrt -lpthread -lm -ldl -lc')
      : $^O eq 'darwin' ? '-lSystem -lc -lm'
      : '';
    $build->runtime_prop->{version} = $version;
    $build->runtime_prop->{cflags} = "-I$prefix/include";
    $build->runtime_prop->{cflags_static} = "-I$prefix/include";
    $build->runtime_prop->{libs} = "-L$prefix/lib -lcorvus_json_schema $private";
    $build->runtime_prop->{libs_static} = "-L$prefix/lib -lcorvus_json_schema $private";
    $build->runtime_prop->{capi_target} = $target;
  });
};
