#!/usr/bin/env perl
use strict;
use warnings;
use feature qw(say);

our $VERSION = "0.13";

use List::Util qw(first);
use Directory::Iterator;
use Getopt::Long;
use Module::CoreList;

use version 0.77;
my $pVer = version->parse($]);    # parse version from running environment

use App::findeps;

use File::Basename qw(basename);
my $scriptName = basename($0);
my $usage      = <<"EOL";
Usage: $scriptName [ -u ] [ -L yourlib ] FILE | cpanm
  -u | --upgradeAll         : flag it if you want to upgrade all your dependencies
  -L | --myLib [yourLib]    : designate directory name of your library.
                            : then it will be excluding from detection.
                            : defaults to 'lib'

EOL

GetOptions(
    "u|upgradeAll"   => \$App::findeps::Upgrade,
    "L|myLib=s"      => \$App::findeps::myLib,
    "m|makeCpanfile" => \$App::findeps::toCpanfile,
) or die $usage;

die $usage unless @ARGV;

makeCpanfile(@ARGV) if $App::findeps::toCpanfile;

my @list = scan(@ARGV);

die "Ready to run @ARGV\n" unless @list;

say $_ for @list;

exit;

sub scan {
    my @files = @_;
    @files = map { /::/ ? _getPath($_) : $_ } @files;
    my $map  = App::findeps::scan( files => \@files );
    my @list = ();
    foreach my $key ( sort keys %$map ) {
        my $version = $map->{$key};
        my $name    = App::findeps::_name($key);
        my $dist    = $name;
        $dist .= "~$version" if defined $version;
        push @list, $dist;
    }
    return @list;
}

sub makeCpanfile {
    die 'Too many Arguments' if @_ > 1;
    my $file = shift;
    $App::findeps::Upgrade = 1;
    my $name = App::findeps::_name($file);
    $file = _getPath($name) if $file =~ /::/;
    my @list = scan($file);
    my ( @require, @test_require );
    push @require, make_line($_) for @list;

    my $list = Directory::Iterator->new('t');
    while ( $list->next ) {
        my $test = scan( $list->get );
        push @test_require, make_line($test) unless first { $test =~ /^$_/ } @list, $name;
    }

    local $" = "\n";
    print <<"EOL";
requires 'perl', '$pVer';

@require
EOL
    local $" = "\n    ";
    print <<"EOL" if @test_require;
on 'test' => sub {
    @test_require
};
EOL
    exit;
}

sub make_line {
    my ( $name, $version ) = split '~', shift;
    return if Module::CoreList->is_core( $name, $version, $pVer );
    $version = $version ? ", '$version'" : '';
    return "requires '$name'$version;";
}

sub _getPath {
    local $_ = shift;
    s!::!/!g;
    "lib/$_.pm";
}

__END__

=encoding utf-8

=head1 NAME

findeps - A simple command-line tool that makes ready to run Perl script on any environment

=head1 SYNOPSIS

 $ findeps your_product.pl | cpanm
 $ findeps Plack.psgi | cpanm
 $ findeps index.cgi | cpanm
 $ findeps t/00_compile.t | cpanm
 
 #On directory of the modules you made
 $ findeps Your::Module | cpanm

Now you're ready to run the product you've made with many modules
without installing them every single time

=head1 DESCRIPTION

C<findeps> is a command line tool that resolves dependencies from too many Perl modules

L<scandeps.pl> requires you to have L<CPANPLUS> that was deprecated in v5.17.9 and removed from v5.19.0 on CORE

So I did I<reinvent> what requires just only L<cpanm>.

=over

=item -u --upgradeAll OPTION

 $ findeps -u index.cgi | cpanm

tries to upgrade modules you've already installed to the newest

=item -L --myLib OPTION

 $ findeps -L=modules Plack.psgi | cpanm

If you have a local directory named 'modules' not to be 'lib',
you can choose it and the modules in there are ignored
because you've already holden them.

=back

=head1 DANGEROUS OPTION

  $ findeps --makeCpanfile Some::Module >| cpanfile

It may be useful when you build a new module with L<Minilla>
but B<NOT recommended> yet

=head1 SEE ALSO

=over

=item L<cpanm>

=item L<scandeps.pl>

=back

=head1 LICENSE

Copyright (C) worthmine.

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

=head1 AUTHOR

Yuki Yoshida(L<worthmine|https://github.com/worthmine>)

=cut