use alienfile;
use Config;

# The corvus-json-schema C library (src-rs/corvus-json-schema-capi), version 0.1.7 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.7';

my %digest = (
  'aarch64-pc-windows-msvc'    => 'e74eb3822fa0730654045c2cf455a899bef90f90b6f183e60ee6a36416555a94',
  'aarch64-unknown-linux-gnu'  => '00ad0bce8b1ae0d2c7657de191ea942293ab606bdc5f98f331b018e03b5dff10',
  'aarch64-unknown-linux-musl' => '92b6d6ba48fcfcbbedbf2d0bbb337d60e075d6289efd4a86ee7097e939d637ce',
  'universal2-apple-darwin'    => '136d538b5ebe117fa6233c224c58cf6ff939149ec041c0c9317bcf4194c1d3aa',
  'x86_64-pc-windows-msvc'     => 'b7c1e00459dc0018b6986f4bb38e2d4ad70b22d2cde2b6c84b06a8e57fdc70be',
  'x86_64-unknown-linux-gnu'   => '290ada3bfedaf466b975f6992ff525629e7402669f1d1efbf4c1dd9c164d6a24',
  'x86_64-unknown-linux-musl'  => '0830191606e99b1ee8bf3e9dd013c9e44bce19598dfbe45a235a054474e0cd45',
);

# 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;
  });
};
