#!/usr/bin/env perl

my $copyright = <<'COPYRIGHT';
# Copyright 2021 by Christian Jaeger <ch@christianjaeger.ch>
# Published under the same terms as perl itself
COPYRIGHT

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

my ($email_full) = $copyright =~ / by ([^\n]*)/s;

my ($mydir, $myname);

BEGIN {
    $0 =~ /(.*?)([^\/]+)\z/s or die "?";
    ($mydir, $myname) = ($1, $2);
}

sub usage {
    print STDERR map {"$_\n"} @_ if @_;
    print "$myname command [args]

  Print and read a Perl syntax file containing stat values of all files under
  dirpath, recursively:

   { \$path => [ lstat \$path ], ... }

  Does not follow symlinks when recursing.

  Commands:

    print-tree \$basedir

        prints the stat values at \$basedir to stdout.

    repl \$file...

        open a repl with the parsed \$file... in \@ts


  Options:

    --no-chdir

       By default, treestat uses chdir in print-tree then use '.' as
       the base folder name. This option turns that off.

  ($email_full)
";
    exit(@_ ? 1 : 0);
}

use Getopt::Long;
our $verbose = 0;
my $opt_no_chdir;

#our $opt_dry;
GetOptions(
    "verbose"  => \$verbose,
    "help"     => sub {usage},
    "no-chdir" => \$opt_no_chdir,

    #"dry-run"=> \$opt_dry,
) or exit 1;
usage unless @ARGV >= 1;

use lib '/opt/functional-perl/lib';    # new stuff, or when fperl_noinstall
use Chj::xperlfunc qw(xlstat xprintln xprint xgetfile_utf8 xchdir);
use FP::IOStream qw(xdirectory_paths);
use FP::Ops qw(string_cmp);
use FP::List qw(cons null);
use FP::Lazy;
use FP::Stream ":all";
use Chj::singlequote qw(singlequote);
use FP::Show;
use FP::Repl;
use JSON::PP qw(encode_json decode_json);

sub tree_to_records ($dirpath, $tail) {
    lazy {
        xdirectory_paths($dirpath, \&string_cmp)->fold_right(
            sub ($path, $tail) {
                my $s = xlstat $path;
                cons([$path, [@$s]],
                    $s->is_dir ? tree_to_records($path, $tail) : $tail)
            },
            $tail
        )
    }
}

sub print_tree ($dirpath) {
    my $base;
    if ($opt_no_chdir) {
        $base = $dirpath;
    } else {

        # Should we fork to scope the effect?
        xchdir $dirpath;
        $base = ".";
    }

    # Stream out JSON (should make a module for this!):
    binmode STDOUT, ":encoding(UTF-8)" or die "binmode: $!";
    xprintln "{";

    tree_to_records($base, null)->for_each_with_islast(
        sub ($record, $islast) {
            my ($path, $s_ary) = @$record;
            xprintln " ", encode_json($path), ": ", encode_json($s_ary),
                ($islast ? () : ",");
        }
    );

    xprintln "}";
}

sub load_json ($path) {
    decode_json xgetfile_utf8($path)
}

sub parse_treestat ($path) {
    my $hash = load_json($path);

    # turn values back into stat objects
    for (values %$hash) {
        @$_ == 13
            or die "invalid array with other than 13 elements: " . show($_);
        bless $_, 'Chj::xperlfunc::xstat';
    }
    $hash
}

sub trees_repl {
    my @ts = map { parse_treestat $_ } @_;
    repl;
}

my $command = shift @ARGV;

my $proc
    = +{ "print-tree" => \&print_tree, "repl" => \&trees_repl, }->{$command}
    or usage "unknown command '$command'";

$proc->(@ARGV);

#use Chj::ruse;
#use Chj::Backtrace;

