#!/usr/bin/env perl

# Copyright (c) 2015-2020 Christian Jaeger, copying@christianjaeger.ch
# This is free software. See the file COPYING.md that came bundled
# with this file.

use strict;
use warnings;
use warnings FATAL => 'uninitialized';
use experimental "signatures";

# find modules from functional-perl working directory (not installed)
use Cwd 'abs_path';
our ($mydir, $myname);

BEGIN {
    my $location = (-l $0) ? abs_path($0) : $0;
    $location =~ /(.*?)([^\/]+?)_?\z/s or die "?";
    ($mydir, $myname) = ($1, $2);
}
use lib "$mydir/../lib";
use lib "$mydir/../meta";

sub usage {
    print "usage: $myname

  Criticizes the functional-perl code base.

  Options:
    --repl
";
    exit 1;
}

use Getopt::Long;
our $verbose = 0;
our $opt_repl;
GetOptions(
    "verbose" => \$verbose,
    "help"    => sub {usage},
    "repl"    => \$opt_repl,
) or exit 1;
usage if @ARGV;

use Perl::Critic;
use FunctionalPerl::ModuleList;
use Chj::Backtrace;
use FP::Array ":all";
use FP::Stream ":all";
use FP::PureArray;
use Chj::xperlfunc qw(xprintln);
use FP::Ops "the_method";
use Chj::ruse;
use FP::Repl;

{

    package PFLANZE::Result;
    use FP::Struct ["path"];

    sub prefix($self) {
        $self->path . "\t"
    }
    _END_;
}
{

    package PFLANZE::ERR;
    use FP::Struct ["message"], "PFLANZE::Result";

    sub string($self) {
        $self->prefix . $self->messsage
    }
    _END_;
}
{

    package PFLANZE::OK;
    use FP::Struct ["critiques"], "PFLANZE::Result";

    sub has_critique($self) {
        @{ $self->critiques } > 0
    }

    sub string($self) {
        my $p = $self->prefix;
        $self->critiques->map (
            sub($c) {
                "$p$c"
            }
        )->strings_join("");
    }
    _END_;
}

sub critique($path) {
    eval {
        my $critic = Perl::Critic->new();
        PFLANZE::OK->new($path, purearray $critic->critique($path));
    } || PFLANZE::ERR->new($path, "$@");
}

our $critiques = array_to_stream(modulepathlist)->map(*critique);

if ($opt_repl) {
    repl;
} else {
    $critiques->filter(the_method "has_critique")->for_each(
        sub($c) {
            xprintln $c->string
        }
    );
}

