#!/usr/bin/env perl
#ABSTRACT: Create a Singularity/Apptainer image from micromamba
#PODNAME: make_image_from_bioconda

use v5.12;
use warnings;
use Getopt::Long qw(:config no_ignore_case);
use Pod::Usage;

my $output  = undef;
my $move   = 0;
my $def_file = undef;
my $dest = '/qib/platforms/Informatics/transfer/outgoing/singularity/core/';
my $verbose = 0;
GetOptions(
    'o|output=s'  => \$output,
    'd|def=s'     => \$def_file,
    'm|move'      => \$move,
);
my ($package, $version) = @ARGV;

if ( ! -d $dest ) {
    die "Destination directory $dest does not exist.\n";
}
if (not defined $package) {
    pod2usage(-verbose => 1);
}

$version = last_ver($package) if not defined $version;

if (not defined $output) {
    $output = $package . '__' . $version . '.simg';
}

say STDERR "
==============================
Package:     $package
Version:     $version
Output:      $output
Destination: $dest/$output
==============================
";

if ( ! connected() ) {
    say STDERR "[WARNING] Not connected to the internet, are you in the software node?";
}

if ( defined $def_file and -e $def_file) {
    # Use the provided definition file
    say STDERR "Using provided definition file $def_file. [EXPERIMENTAL]";
} else {
    my $def_template = template();
    my $data = {
        'package' => $package,
        'version' => $version,
    };
    my $def = fill_template($def_template, $data);
    my $rand_str = rand_string(38);
    my $tmp_file = $ENV{TMPDIR} // '/tmp' . '/' . $package . '_' . $rand_str . '.def';
    open(my $fh, ">", $tmp_file);
    print $fh $def;
    close $fh;

    $def_file = $tmp_file;
    say STDERR "Definition file created at $def_file.";
}

my $cmd = "sudo singularity build $output $def_file 2>&1 > $def_file.log";

# Execute cmd redirecting STDERR to STDOUT and STDOUT to a file
# This is to avoid the error message from micromamba
# "WARNING: apt does not have a stable CLI interface. Use with caution in scripts."
if (system($cmd) != 0) {
    die "Error building image.\n";
} 

if ($move) {
    my $mv_cmd = "mv $output $dest";
    if (system($mv_cmd) != 0) {
        die "Error moving image to $dest.\n";
    }
}
sub last_ver {
    my $channel = 'bioconda';
    my $package = shift;
    my $answer = `curl --silent -X GET --header 'Accept: application/json' 'https://api.anaconda.org/package/$channel/$package'| grep latest_version | cut -f4 -d\\"`;
    chomp($answer);
    return $answer;

}

sub connected {
    my $cmd = "curl ifconfig.me";
    my $ip = `$cmd`;
    if ($ip =~/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) {
        return 1;
    } else {
        return 0;
    }
}
sub fill_template {
    my ($template, $data) = @_;

    # Regular expression to match variables like {name:=customer}
    while ($template =~ /\{([^}]+)\}/g) {
        my $variable = $1;

        # Split variable into name and default value
        my ($name, $default) = split /:=/, $variable, 2;

        # If the variable exists in the data hash, replace it
        if (exists $data->{$name}) {
            $template =~ s/\{$variable\}/$data->{$name}/g;
        } elsif (defined $default) {
            # If there's a default value, use it
            $template =~ s/\{$variable\}/$default/g;
        } else {
            die "Variable '$variable' is unsubstituted and has no default value.";
        }
    }

    return $template;
}


sub template {
my $template =<<'EOF';
Bootstrap: docker
From: mambaorg/micromamba:latest

%post
    #Preparing container for: {package} {version}
    # Core Bioinformatics, using NBI::Slurm
    echo "[1] Create environment"
    micromamba create --yes -p /opt/conda/envs/package_env/
    echo "[2] Install package dependencies"
    micromamba install --yes --only-deps --prefix /opt/conda/envs/package_env/ -c conda-forge -c bioconda -c defaults {package}={version}
    ls /opt/conda/envs/package_env/bin > /list_deps.txt
    echo "[3] Install package"
    micromamba install --yes --prefix /opt/conda/envs/package_env/ -c conda-forge -c bioconda -c defaults {package}={version}
    ls /opt/conda/envs/package_env/bin > /list_all.txt
    echo "[4] Clean environment"
    micromamba clean --all --yes
    echo "[5] Create binaries list: /etc/binaries.txt"
    sort /list_all.txt > /tmp/list_all.txt
    sort /list_deps.txt > /tmp/list_deps.txt
    comm /tmp/list_all.txt /tmp/list_deps.txt -2 -3 | sort > /etc/binaries.txt
    rm /list_all.txt /list_deps.txt
    rm /tmp/*txt
    echo "[6] Finalize"
    {post:=#Nothing to add}

%environment
    export PATH=/opt/conda/envs/package_env/bin:$PATH

EOF

return $template;
}

sub rand_string {
    my $valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    my $length = shift;
    my $random_string = "";
    my $num_chars = length($valid_chars);
    for (my $i = 0; $i < $length; $i++) {
        my $random_position = int(rand($num_chars));
        $random_string .= substr($valid_chars, $random_position, 1);
    }
    return $random_string;
}

__END__

=pod

=encoding UTF-8

=head1 NAME

make_image_from_bioconda - Create a Singularity/Apptainer image from micromamba

=head1 VERSION

version 0.6.3

=head1 SYNOPSIS

    make_image [options] package_name package_version

=head1 DESCRIPTION

Create a Singularity/Apptainer image from a single micromamba package

=head1 OPTIONS

=over 4

=item B<-o, --output> I<FILENAME>

The name of the output image file. Default: singularity.simg

=item B<-d, --def> I<FILENAME>

The name of the definition file [optional]

=item B<-m, --move>

Move to the Core Bioinformatics repository

=back

=head1 AUTHOR

Andrea Telatin <proch@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2023 by Andrea Telatin.

This is free software, licensed under:

  The MIT (X11) License

=cut
