#!/usr/bin/env perl
use strictures 2;

use GitLab::API::v4;
use GitLab::API::v4::Constants qw( :all );
use GitLab::API::v4::Config;

use Log::Any qw( $log );
use Log::Any::Adapter;
use Log::Any::Adapter::Screen;
use Try::Tiny;
use JSON;

use Getopt::Long qw( GetOptions );
use Pod::Usage qw( pod2usage );

Getopt::Long::Configure(qw(
    gnu_getopt no_ignore_case
    pass_through
));

GetOptions(
    'a|all' => \my $all,

    'h|help'    => \my $help,
    'v|verbose' => \my $verbose,
    'q|quiet'   => \my $quiet,
) or fail('Unable to process options!');

if ($help or @ARGV and $ARGV[0] eq 'help') {
    pod2usage( -verbose => 2 );
    exit 0;
}

my $min_level = 'info';
$min_level = 'trace' if $verbose;
$min_level = 'error' if $quiet;

my $config = GitLab::API::v4::Config->new();

Log::Any::Adapter->set(
    'Screen',
    min_level => $min_level,
    stderr    => 1,
);

my $access_levels = {
    '--access-level-guest'     => $GITLAB_ACCESS_LEVEL_GUEST,
    '--access-level-reporter'  => $GITLAB_ACCESS_LEVEL_REPORTER,
    '--access-level-developer' => $GITLAB_ACCESS_LEVEL_DEVELOPER,
    '--access-level-master'    => $GITLAB_ACCESS_LEVEL_MASTER,
    '--access-level-owner'     => $GITLAB_ACCESS_LEVEL_OWNER,
};

my @args;
my $params = {};
foreach my $arg (@ARGV) {
    if (defined $access_levels->{$arg}) {
        $params->{access_level} = $access_levels->{$arg};
    }
    elsif ($arg =~ m{^--(no-|)?([^\s=]+)(=(.*)|)$}) {
        my ($no, $key, $has_value, $value) = ($1, $2, $3, $4);
        $key =~ s{-}{_}g;
        $value = $has_value ? $value : $no ? 0 : 1;
        $params->{$key} = $value;
    }
    else {
        push @args, $arg;
    }
}

my $method = shift( @args );
fail( 'No method was specified.' ) if !$method;
$method =~ s{-}{_}g;

if ($method eq 'configure') {
    $config->configure();
    exit;
}

try {
    my $api = GitLab::API::v4->new( $config->args() );

    if ($all) {
        @args = ( $method, @args );
        $method = 'paginator';
    }

    my $data = $api->$method(
        @args,
        %$params ? $params : (),
    );

    $data = $data->all() if $all;

    binmode STDOUT, ':utf8';
    my $json = JSON->new->allow_nonref();
    print $json->encode( $data );
}
catch {
    fail( $_ );
};

sub fail {
    $log->fatal( @_ );
    exit 1;
}

__END__

=head1 NAME

gitlab-api-v4 - Command line interface to the GitLab API v4.

=head1 SYNOPSIS

    # Generally:
    gitlab-api-v4 <method> [<arg> ...] [--<param>=<value> ...]
    
    # List all groups:
    gitlab-api-v4 groups
    
    # List information about a project:
    gitlab-api-v4 project <project_id>
    
    # Create an admin user:
    gitlab-api-v4 create-user \
        --email=<email> --password=<password> --username=<username> --name=<name> --admin

=head1 CONFIGURING

You may configure this module with envornment variables, command line options,
and a configuration file.  To setup the configuration file run:

    gitlab-api-v4 configure

This will ask several interactive questions to help you configure this script.
The information, which may include GitLab authentication tokens, is stored in
C<~/.gitlab-api-v4.json>.

Read more at L<GitLab::API::v4::Config>.

=head1 OPTIONS

=head2 method

    <method>

The API method to call (one of the methods documented in
L<GitLab::API::v4>).

=head2 args

    <arg> ...

Any arguments that the L</method> requires.

=head2 params

    --<param>=<value> ...

Any parameters that the L</method> accepts.

=head2 access level

    --access-level-guest
    --access-level-reporter
    --access-level-developer
    --access-level-master
    --access-level-owner

=head2 all

    --all

Retrieves all results when the results would normally be paged.

=head1 AUTHORS

See L<GitLab::API::v4/AUTHOR> and L<GitLab::API::v4/CONTRIBUTORS>.

=head1 LICENSE

This script is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.