#!/usr/bin/env perl

use warnings;
use strict;

use Data::Dumper;
use Carp;

use 5.010;

use File::Path qw/make_path/;
use DateTime;
use File::Spec::Functions     qw/catfile/;
use Bio::Gonzales::Util::File qw/slurpc/;
use Cwd                       qw/fastcwd/;
use File::Touch;
use IO::Prompt::Tiny qw/prompt/;
use Getopt::Long::Descriptive;
use Bio::Gonzales::Util::Development::File;

our $ANALYSIS_DIR     = 'analysis';
our @STD_PROJECT_DIRS = qw(
  lib
  docs
  data
  analysis
);

our @REQUIRED_PROJECT_DIRS = qw(
  .git
  docs
  analysis
);

my ($opt, $usage) = describe_options(
  '%c %o <cmd> <name>', [ 'help', "print usage message and exit", ],
  [],                   ['<cmd> can be "init, analysis, ls, tag'],
);

print($usage->text), exit if $opt->help;

@ARGV = ('ls') unless (@ARGV >= 1);

my ($cmd, @args) = @ARGV;

my $date = DateTime->today->strftime("%F");

if ($cmd =~ /^i(nit)?/) {
  my $name = shift @args;

  confess 'you have to supply a name' unless ($name);
  confess "name already exists" if (-e $name);

  my @dirs = ($name);
  push @dirs, map { catfile($name, $_) } @STD_PROJECT_DIRS;

  for my $d (@dirs) {
    say STDERR "Creating $d";
    make_path($d);
  }

  chdir $name;

  say STDERR "Creating Makefile";
  open my $make_fh, '>', "Makefile" or confess "Can't open filehandle: $!";
  print $make_fh <<'EOF';
.PHONY: all clean test docs help

help: ## this help
	@perl -nE 'printf "\033[1m\033[36m%-38s\033[0m %s\n", $$1, $$2 if /^([a-zA-Z0-9._-]+):.*?## (.*)$$/' $(MAKEFILE_LIST)

EOF
  $make_fh->close;

  create_readme('.', $name, $date);
  say STDERR "creating git repo";

  open my $gi_fh, '>', '.gitignore' or confess "Can't open filehandle: $!";
  say $gi_fh ".rsync_backup_filter";
  say $gi_fh ".nob2";
  say $gi_fh '/analysis/*/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]*/';
  $gi_fh->close;

  system qw/git init/;
  system qw(git add Makefile README .gitignore);
  system qw/git commit -m/, "initial commit";

  say STDERR "Finished";

} elsif ($cmd =~ /^a(nalysis)?/) {
  my $name = shift @args;

  my $project_dir = find_project_root();
  my $rel_dir;
  my $dir;
  if ($project_dir) {
    $project_dir = File::Spec->rel2abs($project_dir);
    $rel_dir     = catfile($ANALYSIS_DIR, $name);
    $dir         = catfile($project_dir,  $rel_dir);

  } else {
    $rel_dir = $name;
    $dir     = catfile(File::Spec->rel2abs('.'), $rel_dir);
  }
  say STDERR "Creating $dir";
  if (-e $dir) {
    my $answer = prompt("analysis dir $dir already exists, overwrite? (y/n)", "n");
    exit if ($answer !~ /^y/i);
  }
  make_path($dir);

  say STDERR "Creating $dir/bin";
  make_path(catfile($dir, 'bin'));

  say STDERR "Creating $dir/data";
  make_path(catfile($dir, 'data'));

  say STDERR "Creating $dir/playground";
  make_path(catfile($dir, 'playground'));

  chdir $dir;
  say STDERR "Creating Makefile";
  open my $make_fh, '>', "Makefile" or confess "Can't open filehandle: $!";
  print $make_fh <<'EOF';
.PHONY: all dir help

ifndef ANALYSIS_VERSION
  ifneq ("$(wildcard av)","")
    ANALYSIS_VERSION=$(shell cat av)
  else
    ANALYSIS_VERSION="."
  endif
endif

$(info analysis version: $(ANALYSIS_VERSION))
# optional
#export ANALYSIS_VERSION

AV=$(ANALYSIS_VERSION)
NAME=$(lastword $(subst /, ,$(abspath .)))

all: dir

dir:
	@[ -d $(AV) ] || mkdir $(AV)

help: ## this help
	@perl -nE 'printf "\033[1m\033[36m%-38s\033[0m %s\n", $$1, $$2 if /^([a-zA-Z0-9._-]+):.*?## (.*)$$/' $(MAKEFILE_LIST)

EOF
  $make_fh->close;

  open my $av_fh, '>', 'av' or confess "Can't open filehandle: $!";
  say $av_fh $date;
  $av_fh->close;

  open my $rsync_fh, '>', '.rsync_backup_filter' or confess "Can't open filehandle: $!";
  say $rsync_fh '- [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]*/';
  $rsync_fh->close;

  say STDERR "Creating IO files dictionary";
  open my $gonzconf_fh, '>', 'gonz.conf.yml' or die "Can't open filehandle: $!";
  say $gonzconf_fh '---';
  close $gonzconf_fh;
  #touch("INDEX");

  (my $pretty_name = $name);    # =~ s/^\d+_//;
  create_readme('.', $pretty_name, $date);

  #system qw/git init/;
  system qw/git add Makefile README av gonz.conf.yml/;
  system qw/git commit -m/, "added $name";

  if ($project_dir) {
    say STDERR 'updating project makefile';
    open my $main_mkf_fh, '>>', catfile($project_dir, 'Makefile') or confess "Can't open filehandle: $!";
    say $main_mkf_fh "";
    say $main_mkf_fh "# created on $date";
    say $main_mkf_fh "$name: ## run $name analysis";
    say $main_mkf_fh "\tcd $rel_dir && \$(MAKE)";
    $main_mkf_fh->close;
  } else {
    say STDERR 'NOT updating project makefile';
  }
  say STDERR "Finished";
} elsif ($cmd eq 'ls') {
  my $dir = catfile(find_project_root(), $ANALYSIS_DIR);

  my @all_analysis_runs;
  confess "could not find $dir" unless (-d $dir);

  opendir(my $dh, $dir) || confess "could not open dir $dir";
  my @analysis_dirs = readdir($dh);
  @analysis_dirs = grep { !/^\./ && -d catfile($dir, $_) } @analysis_dirs;
  closedir($dh);

  for my $ad (@analysis_dirs) {
    my $abs_ad = catfile($dir, $ad);
    opendir(my $adh, $abs_ad) || confess "could not open $abs_ad";
    my @runs = grep { /^\d{4}-\d\d-\d\d$/ && -d catfile($abs_ad, $_) } readdir($adh);
    closedir($adh);
    push @all_analysis_runs, map { [ $ad, $_ ] } @runs;
  }
  @all_analysis_runs = sort { $a->[1] cmp $b->[1] } @all_analysis_runs;

  for my $ar (@all_analysis_runs) {
    say $ar->[1] . "    " . catfile(@$ar);
  }
} elsif ($cmd eq 'tag') {
  confess "no analysis version file found" unless (-f 'av');

  my $analysis_version = (slurpc('av'))[0];
  my $curdir           = (File::Spec->splitpath(fastcwd))[2];
  say $curdir . "_" . $analysis_version;
} else {
  print($usage->text), exit;
}

sub create_readme {
  my ($path, $name, $date) = @_;

  say STDERR "Creating README file";
  open my $readme_fh, '>', catfile($path, 'README') or confess "Can't open filehandle: $!";
  say $readme_fh uc($name);
  say $readme_fh "=" x length($name);
  say $readme_fh "";
  say $readme_fh "Joachim Bargsten <jw\@bargsten.org>";
  say $readme_fh "$name erstellt am $date.";
  say $readme_fh "\n";
  $readme_fh->close;
}

sub find_project_root {
  my $home = Bio::Gonzales::Util::Development::File::find_root(
    { location => '.', dirs => [@REQUIRED_PROJECT_DIRS], files => ['Makefile'] });

  unless (defined($home)) {
    carp("Could not find project home, using current dir");
    return;
  }

  return $home;
}
