#!/usr/local/bin/perl6
use Shell::Command;
use Panda;

sub listprojects($panda, :$installed, :$verbose) {
    my $es        = $panda.ecosystem;
    my @projects  = $es.project-list.sort.map: { $es.get-project($_) };
       @projects .= grep({ $es.project-get-state($_) ne 'absent' })
                    if $installed;
    my @saved     = @projects.map({ $es.project-get-saved-meta($_) || {} });
    my $max-name  = @projects».name».chars.max;
    my $max-ver   = @projects».version».chars.max;
    my $max-rev   = @saved.map({ $_<source-revision> // '?'})».chars.max;

    for @projects -> $x {
        my $s = do given $es.project-get-state($x) {
            when 'installed'     { '[installed]' }
            when 'installed-dep' { '-dependency-' }
            default              { '' }
        }

        my $meta = $s ?? $es.project-get-saved-meta($x) !! $x.metainfo;
        my $url  = $meta<source-url> // $meta<repo-url> // 'UNKNOWN';
        my $rev  = $meta<source-revision> // '?';
        my $ver  = $meta<version>;

        if ($verbose) {
            printf "%-{$max-name}s  %-12s  %-{$max-ver}s  %-{$max-rev}s  %s\n",
               $x.name, $s, $ver, $rev, $url;
        }
        else {
            printf "%-{$max-name}s  %-12s\n",
               $x.name, $s;
        }
    }
}

sub wrap ($str) {
    return $str.comb(/ . ** 0..40 [ << | $ ]/).grep({ .chars > 0 }).join("\n" ~ " " x 36);
}

sub search-projects($panda, $string) {
    for $panda.ecosystem.project-list -> $project {
        my $p = $panda.ecosystem.get-project($project);
        next unless $p.name ~~ /:i $string / || $p.metainfo<description> ~~ /:i $string /;
        printf "%-24s %-10s %s\n",$p.name,$p.version, wrap($p.metainfo<description>);
    }
}

sub projectinfo($panda, @args) {
    for @args -> $p {
        my $x = $panda.ecosystem.get-project($p);
        if $x {
            my $state = $panda.ecosystem.project-get-state($x);
            say 'PROJECT LIST:';
            say $x.name => $x.version;
            say 'Depends on:' => $x.dependencies.Str if $x.dependencies;
            given $state {
                when 'installed'     {
                    say 'State' => 'installed';
                }
                when 'installed-dep' {
                    say 'State' => 'installed as a dependency';
                }
            }
            for $x.metainfo.kv -> $k, $v {
                if $k ~~ none('version', 'name', 'depends') {
                    say $k.ucfirst => $v;
                }
            }
            if $state ~~ /^ 'installed' / {
                say 'INSTALLED VERSION:';
                .say for $panda.ecosystem.project-get-saved-meta($x).pairs.sort;
            }
            say '';
        } else {
            say "Project '$p' not found"
        }
    }
}

# default opts for MAIN
if %*ENV<PANDA_DEFAULT_OPTS> {
    @*ARGS = %*ENV<PANDA_DEFAULT_OPTS> ~ (@*ARGS ?? ' ' ~ @*ARGS !! '');
}

# initialize the Panda object
my $panda;
{
    my $pandadir;
    my $destdir = %*ENV<DESTDIR>;
    $destdir = "{cwd}/$destdir" if defined($destdir) &&  $*OS ne 'MSWin32' && $destdir !~~ /^ '/' /;
    for grep(*.defined, $destdir, %*CUSTOM_LIB<site home>) -> $prefix {
        $destdir  = $prefix;
        $pandadir = "$prefix/panda";
        try mkpath $pandadir unless $pandadir.IO ~~ :d;
        last if $pandadir.path.w
    }
    unless $pandadir.path.w {
        die "Found no writable directory into which panda could be installed";
    }

    $panda = Panda.new(
        srcdir       => "$pandadir/src",
        destdir      =>  $destdir,
        statefile    => "$pandadir/state",
        projectsfile => "$pandadir/projects.json"
    );
}

# allow switches after positionals
@*ARGS = @*ARGS.grep(/^ '-'/), @*ARGS.grep(/^ <-[-]>/);

#= Install the specified modules
multi MAIN ('install', *@modules, Bool :$notests, Bool :$nodeps) {
    for @modules -> $x {
        try {
            $panda.resolve($x, :$notests, :$nodeps);
            CATCH { say $! }
        };
    }
}

#= List all available modules
multi MAIN ('list', Bool :$installed, Bool :$verbose) {
    listprojects($panda, :$installed, :$verbose);
}

#= Update the module database
multi MAIN ('update') {
    $panda.ecosystem.update;
}

#= Display information about specified modules
multi MAIN ('info', *@modules) {
    projectinfo($panda, @modules);
}

#= Search the name/description
multi MAIN ('search', $pattern) {
    search-projects($panda, $pattern);
}

# vim: ft=perl6
