package App::cpm::Builder::Static;
use v5.24;
use warnings;
use experimental qw(lexical_subs signatures);

use CPAN::Meta;
use ExtUtils::Config 0.003;
use ExtUtils::Helpers 0.020 qw/make_executable split_like_shell man1_pagename man3_pagename detildefy/;
use ExtUtils::Install qw/pm_to_blib install/;
use ExtUtils::InstallPaths 0.002;
use File::Basename qw/dirname/;
use File::Find ();
use File::Path qw/mkpath/;
use File::Spec::Functions qw/catfile catdir rel2abs abs2rel splitdir curdir/;
use Getopt::Long 2.36 qw/GetOptionsFromArray/;

sub read_file {
	my ($filename) = @_;
	open my $fh, '<', $filename or die "Could not open $filename: $!\n";
	return do { local $/; <$fh> };
}

sub new {
    my($class, %args) = @_;
    bless {
        meta => $args{meta},
    }, $class;
}

sub meta {
    my $self = shift;
    $self->{meta};
}

sub manify {
	my ($input_file, $output_file, $section, $opts) = @_;
	return if -e $output_file && -M $input_file <= -M $output_file;
	my $dirname = dirname($output_file);
	mkpath($dirname, $opts->{verbose}) if not -d $dirname;
	require Pod::Man;
	Pod::Man->new(section => $section)->parse_from_file($input_file, $output_file);
	print "Manifying $output_file\n" if $opts->{verbose} && $opts->{verbose} > 0;
	return;
}

sub find {
	my ($pattern, $dir) = @_;
	my @ret;
	File::Find::find(sub { push @ret, $File::Find::name if /$pattern/ && -f }, $dir) if -d $dir;
	return @ret;
}

sub contains_pod {
	my ($file) = @_;
	return unless -T $file;
	return read_file($file) =~ /^\=(?:head|pod|item)/m;
}

my %actions = (
	build => sub {
		my %opt = @_;
		my %modules = map { $_ => catfile('blib', $_) } find(qr/\.pm$/, 'lib');
		my %docs    = map { $_ => catfile('blib', $_) } find(qr/\.pod$/, 'lib');
		my %scripts = map { $_ => catfile('blib', $_) } find(qr/(?:)/, 'script');
		my %sdocs   = map { $_ => delete $scripts{$_} } grep { /.pod$/ } keys %scripts;
		my %dist_shared    = map { $_ => catfile(qw/blib lib auto share dist/, $opt{meta}->name, abs2rel($_, 'share')) } find(qr/(?:)/, 'share');
		my %module_shared  = map { $_ => catfile(qw/blib lib auto share module/, abs2rel($_, 'module-share')) } find(qr/(?:)/, 'module-share');
		pm_to_blib({ %modules, %docs, %scripts, %dist_shared, %module_shared }, catdir(qw/blib lib auto/));
		make_executable($_) for values %scripts;
		mkpath(catdir(qw/blib arch/), $opt{verbose});

		if ($opt{install_paths}->install_destination('bindoc') && $opt{install_paths}->is_default_installable('bindoc')) {
			my $section = $opt{config}->get('man1ext');
			for my $input (keys %scripts, keys %sdocs) {
				next unless contains_pod($input);
				my $output = catfile('blib', 'bindoc', man1_pagename($input));
				manify($input, $output, $section, \%opt);
			}
		}
		if ($opt{install_paths}->install_destination('libdoc') && $opt{install_paths}->is_default_installable('libdoc')) {
			my $section = $opt{config}->get('man3ext');
			for my $input (keys %modules, keys %docs) {
				next unless contains_pod($input);
				my $output = catfile('blib', 'libdoc', man3_pagename($input));
				manify($input, $output, $section, \%opt);
			}
		}
                1;
	},
	test => sub {
		my %opt = @_;
		die "Must run `./Build build` first\n" if not -d 'blib';
		require TAP::Harness::Env;
		my %test_args = (
			(verbosity => $opt{verbose}) x!! exists $opt{verbose},
			(jobs => $opt{jobs}) x!! exists $opt{jobs},
			(color => 1) x !!-t STDOUT,
			lib => [ map { rel2abs(catdir(qw/blib/, $_)) } qw/arch lib/ ],
		);
		my $tester = TAP::Harness::Env->create(\%test_args);
		$tester->runtests(sort +find(qr/\.t$/, 't'))->has_errors and return;
                1;
	},
	install => sub {
		my %opt = @_;
		die "Must run `./Build build` first\n" if not -d 'blib';
		install($opt{install_paths}->install_map, @opt{qw/verbose dry_run uninst/});
                1;
	},
);

sub build {
	my $self = shift;
	my $action = @_ && $_[0] =~ /\A\w+\z/ ? shift @_ : 'build';
	die "No such action '$action'\n" if not $actions{$action};
	my %opt;
	GetOptionsFromArray([@$_], \%opt, qw/install_base=s install_path=s% installdirs=s destdir=s prefix=s config=s% uninst:1 verbose:1 dry_run:1 pureperl-only:1 create_packlist=i jobs=i/) for ($self->{env}, $self->{configure_args}, \@_);
	$_ = detildefy($_) for grep { defined } @opt{qw/install_base destdir prefix/}, values %{ $opt{install_path} };
	@opt{ 'config', 'meta' } = (ExtUtils::Config->new($opt{config}), $self->meta);
	$actions{$action}->(%opt, install_paths => ExtUtils::InstallPaths->new(%opt, dist_name => $opt{meta}->name));
}

sub configure {
	my $self = shift;   
	$self->{env} = defined $ENV{PERL_MB_OPT} ? [split_like_shell($ENV{PERL_MB_OPT})] : [];
        $self->{configure_args} = [@_];
	$self->meta->save(@$_) for ['MYMETA.json'], [ 'MYMETA.yml' => { version => 1.4 } ];
}

1;

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by Leon Timmermans, David Golden.

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

=cut
