package Pcore::Dist::Build::Deploy;

use Pcore -class;
use Config;

has dist => ( required => 1 );    # InstanceOf ['Pcore::Dist']

has deps       => ();
has install    => ();
has devel      => ();
has recommends => ();
has suggests   => ();
has verbose    => ();

# TODO under windows acquire superuser automatically with use Win32::RunAsAdmin qw[force];

sub BUILDARGS ( $self, $args ) {
    $args->{devel} = $args->{recommends} = $args->{suggests} = 1 if $args->{all};

    return $args;
}

sub run ($self) {
    my $chdir_guard = P->file->chdir( $self->{dist}->{root} );

    # deps
    exit 3 if $self->{deps} && !$self->_deps;

    # build
    exit 3 if !$self->_build;

    # chmod
    $self->_chmod;

    # install
    exit 3 if $self->{install} && !$self->_install;

    return;
}

sub _chmod ($self) {
    print 'chmod ... ';

    if ( !$MSWIN ) {
        for my $path ( ( P->path->read_dir( max_depth => 0 ) // [] )->@* ) {

            # directory
            if ( -d $path ) {
                P->file->chmod( 'rwxr-xr-x', $path ) or say "$!: $path";
            }

            # file
            else {
                my $is_exe;

                if ( !defined $path->{suffix} && ( $path->{dirname} eq 'bin' || $path->{dirname} eq 'script' ) ) {
                    $is_exe = 1;
                }
                elsif ( defined $path->{suffix} && ( $path->{suffix} eq 'sh' || lc $path->{suffix} eq 'pl' || $path->{suffix} eq 't' ) ) {
                    $is_exe = 1;
                }

                # executable script
                if ($is_exe) {
                    P->file->chmod( 'rwxr-xr-x', $path ) or say "$!: $path";
                }

                # non-executable file
                else {
                    P->file->chmod( 'rw-r--r--', $path ) or say "$!: $path";
                }
            }

            chown $>, $), $path or say "$!: $path";    # EUID, EGID
        }
    }

    say 'done';

    return;
}

sub _deps ($self) {
    if ( -f 'cpanfile' ) {
        my @args = (                                   #
            'cpanm',
            '--with-feature', ( $MSWIN ? 'windows' : 'linux' ),
            ( $self->{devel}      ? '--with-develop'    : () ),
            ( $self->{recommends} ? '--with-recommends' : () ),
            ( $self->{suggests}   ? '--with-suggests'   : () ),
            ( $self->{verbose}    ? '--verbose'         : () ),
            '--metacpan', '--installdeps', q[.],
        );

        say join $SPACE, @args;

        P->sys->run_proc( \@args ) or return;
    }

    return 1;
}

sub _build ($self) {
    eval {
        for my $file ( ( P->path("$self->{dist}->{root}/lib")->read_dir( max_depth => 0, abs => 1, is_dir => 0 ) // [] )->@* ) {
            if ( $file =~ /[.]PL\z/sm ) {
                my $res = P->sys->run_proc( [ $^X, $file, $file =~ s/[.]PL\z//smr ] );

                if ( !$res ) {
                    say qq["$file" return ] . $res;

                    die;
                }
            }
        }
    };

    return $@ ? 0 : 1;
}

sub _install ($self) {
    if ( !P->sys->is_superuser ) {
        say qq[Root privileges required to deploy pcore at system level.];

        return;
    }

    my $canon_dist_root = P->path( $self->{dist}->{root} );

    my $canon_bin_dir = "$canon_dist_root/bin";

    my $workspace_dir_canon = P->path("$canon_dist_root/../")->to_abs;

    if ($MSWIN) {
        if ( $self->{dist}->is_pcore ) {

            # set $ENV{PERL5LIB}
            P->sys->run_proc(qq[setx.exe /M PERL5LIB "$canon_dist_root/lib"]) or return;

            say qq[%PERL5LIB% updated];

            # set $ENV{WORKSPACE}
            P->sys->run_proc(qq[setx.exe /M WORKSPACE "$workspace_dir_canon"]) or return;

            say qq[%WORKSPACE% updated];
        }

        # update $ENV{PATH}
        if ( -d $canon_bin_dir ) {
            require Win32::TieRegistry;

            my @system_path;

            for my $path ( grep { $_ && !/\A\h+\z/sm } split /$Config{path_sep}/sm, Win32::TieRegistry->new('LMachine\SYSTEM\CurrentControlSet\Control\Session Manager\Environment')->GetValue('PATH') ) {
                my $normal_path = P->path($path);

                push @system_path, $path if $normal_path !~ m[\A\Q$canon_bin_dir\E/\z]sm;
            }

            push @system_path, $canon_bin_dir =~ s[/][\\]smgr;

            $ENV{PATH} = join $Config{path_sep}, @system_path;    ## no critic qw[Variables::RequireLocalizedPunctuationVars]

            P->sys->run_proc(qq[setx.exe /M PATH "$ENV{PATH};"]) or return;

            say qq[%PATH% updated];
        }
    }
    else {
        my $data;

        $data = qq[if ! echo \$PATH | grep -Eq "(^|$Config{path_sep})$canon_bin_dir/?(\$|$Config{path_sep})" ; then export PATH="\$PATH$Config{path_sep}$canon_bin_dir" ; fi\n] if -d $canon_bin_dir;

        if ( $self->{dist}->is_pcore ) {
            $data .= <<"SH";
if ! echo \$PERL5LIB | grep -Eq "(^|$Config{path_sep})$canon_dist_root/lib/?(\$|$Config{path_sep})" ; then export PERL5LIB="$canon_dist_root/lib$Config{path_sep}\$PERL5LIB" ; fi
export WORKSPACE="$workspace_dir_canon"
SH
        }

        if ($data) {
            P->file->write_bin( "/etc/profile.d/@{[lc $self->{dist}->name]}.sh", { mode => 'rw-r--r--' }, \$data );

            say "/etc/profile.d/@{[lc $self->{dist}->name]}.sh installed";
        }
    }

    return 1;
}

1;
## -----SOURCE FILTER LOG BEGIN-----
##
## PerlCritic profile "pcore-script" policy violations:
## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
## | Sev. | Lines                | Policy                                                                                                         |
## |======+======================+================================================================================================================|
## |    3 | 104                  | ErrorHandling::RequireCheckingReturnValueOfEval - Return value of eval not tested                              |
## |------+----------------------+----------------------------------------------------------------------------------------------------------------|
## |    3 | 123, 140, 145, 166   | ValuesAndExpressions::ProhibitInterpolationOfLiterals - Useless interpolation of literal string                |
## |------+----------------------+----------------------------------------------------------------------------------------------------------------|
## |    1 | 154                  | ValuesAndExpressions::RequireInterpolationOfMetachars - String *may* require interpolation                     |
## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
##
## -----SOURCE FILTER LOG END-----
__END__
=pod

=encoding utf8

=head1 NAME

Pcore::Dist::Build::Deploy - deploy distribution

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 ATTRIBUTES

=head1 METHODS

=head1 SEE ALSO

=cut
