#!perl
use 5.008001;
use strict;
use warnings;
use feature 'say';
use App::UpdateCPANfile;
use JSON;

use Getopt::Long qw(:config posix_default no_ignore_case pass_through);

my @first_arguments;
while (defined $ARGV[0] && $ARGV[0] =~ /^[^-]/) {
    push @first_arguments, shift @ARGV;
}

GetOptions(
    \my %options, qw{
    limit=n
    shuffle
    filter=s
    ignore-filter=s
    output=s
    version
});

my @rest_arguments = @ARGV;

my ($command, $cpanfile, $cpanfile_snapshot) = (@first_arguments, @rest_arguments);

if ($options{version}) {
    say $App::UpdateCPANfile::VERSION;
    exit 0;
}

my $app = App::UpdateCPANfile->new($cpanfile, $cpanfile_snapshot, \%options);

my $method = {
    pin => 'pin_dependencies',
    update => 'update_dependencies',
}->{$command // ''};

if ($method) {
    my $changeset = $app->$method;
    if (($options{output} // '') eq 'json') {
        say encode_json([map { $_->as_hashref } @$changeset]);
    } else {
        if (@$changeset) {
            my $operated = {pin => 'Pinned', update => 'Updated'}->{$command};
            say "$operated @{[ scalar @$changeset ]} modules";
            for my $change (@$changeset) {
                say "- @{[ join(' ', $change->package_name => $change->version) ]}";
            }
        }
    }
    exit 0;
} else {
    warn <<'HELP';
Usage
Pin Dependencies:    update-cpanfile pin $PATH_TO_CPANFILE $PATH_TO_CPANFILE_SNAPSHOT
Update Dependencies: update-cpanfile update $PATH_TO_CPANFILE
HELP
    exit 1;
}

__END__

=encoding utf-8

=head1 NAME

update-cpanfile - cpanfile updater

=head1 SYNOPSIS

update-cpanfile has two sub commands.

    $ update-cpanfile pin
    $ update-cpanfile update

=head1 PIN

Pin command aligns the package versions in cpanfile to versions in cpanfile.snapshot.
This operation has no side effects for your project's execution environment, so it is useful to pin the versions before update packages.

    $ update-cpanfile pin $PATH_TO_CPANFILE $PATH_TO_CPANFILE_SNAPSHOT

=head1 UPDATE

    $ update-cpanfile update $PATH_TO_CPANFILE

Update command updates the package versions in cpanfile to latest versions in 02packages.txt.
With this command, you can make your dependant libraries latest.
You may run this command from CI, and create Pull Request when there are some diffs.

Update policy is below.

=over 4

=item * The item is listed in cpanfile.

=item * The item is not a core module.

=item * The item is not a perl.

=back

=head1 TARGET PROJECT

By default, update-cpanfile updates cpanfile in current directory.
To execute for other project in directory, you can specify path of cpanfile and cpanfile.snapshot.

    $ update-cpanfile pin <path_to_cpanfile> <path_to_cpanfile.snapshot>
    $ update-cpanfile update <path_to_cpanfile>

=head1 OPTIONS

=over 4

=item * --limit=n

=item * --filter=FILTER

=item * --ignore-filter=FILTER

=item * --shuffle

=item * --output={text|json}

=item * --version

=back

Default output format is C<text>.
When you set C<--output json>, the output format is like this: [{package_name: PACKAGE_NAME, version: VERSION, path: PATH, dist_name: DIST_NAME}, ...]

    [{"package_name":"File::Copy::Recursive","version":"0.45","path":"D/DM/DMUEY/File-Copy-Recursive-0.45.tar.gz","dist_name":"File-Copy-Recursive"}]


C<shuffle> option works fine with C<--limit=1>. C<--limit=1 --shuffle> will update a random picked package.