#! /usr/bin/env perl6

use v6.c;

use App::Bob;
use App::Bob::Package::Ebuild;
use JSON::Fast;

multi sub MAIN("depend", Str $module, Bool :$skip-install = False)
{
	# Get the meta info
	my %meta = get-meta;

	# Install the new dependency with zef
	if (!$skip-install) {
		my $zef = run « zef --cpan install $module »;

		die "Zef failed, bailing" if 0 < $zef.exitcode;
	}

	# Add the new dependency if its not listed yet
	if (%meta<depends> ∌ $module) {
		%meta<depends>.push: $module;
	}

	# Write the new META6.json
	put-meta(:%meta);

	# And finish off with some user friendly feedback
	say "$module has been added as a dependency to {%meta<name>}";
}

multi sub MAIN("dist", *@paths, Bool :$force = False)
{
	my Str @absolute-paths;

	# Default to the current directory
	if (@paths.elems < 1) {
		@paths.push: ".";
	}

	for @paths -> $path {
		@absolute-paths.push: $path.IO.absolute;
	}

	for @absolute-paths -> $path {
		chdir $path;

		if (!"./META6.json".IO.e) {
			note "No META6.json in {$path}";
			next;
		}

		my %meta = from-json(slurp("./META6.json"));

		my Str $fqdn = get-dist-fqdn(%meta);
		my Str $basename = $*CWD.IO.basename;
		my Str $transform = "s/^\./{$fqdn}/";
		my Str $output = "{$*HOME}/.local/var/6pan/{$fqdn}.tar.gz";

		if ($output.IO.e && !$force) {
			note "Archive already exists: {$output}";
			next;
		}

		my $proc = run(« tar czf {$output} --transform {$transform} --exclude-vcs --exclude-vcs-ignores --exclude=.[^/]* . », :err);

		say "Created {$output}";
	}
}

multi sub MAIN("new", Str $module-name = "", Bool :$git = True)
{
	my Str $name = $module-name;

	# Ask for a module name if one was not supplied yet
	if ($name eq "") {
		$name = ask("Name of the module");
	}

	# Create a directory name for the module
	my $dir-name = "perl6-" ~ $name.subst("::", "-", :g);

	# Make sure it isn't already taken on the local system
	if ($dir-name.IO.e) {
		die "Directory named $dir-name already exists.";
	}

	# Ask the user about some information on the module
	my $author = ask("Your name");
	my $email = ask("Your email address");
	my $perl = ask("Perl 6 version", :default("c"));
	my $description = ask("Module description", :default("Nondescript"));
	my $license = ask("License key", :default("GPL-3.0"));

	# Create the initial %meta
	my %meta = %(
		meta-version => 1,
		perl => "6.$perl",
		name => $name,
		description => $description,
		authors => ("$author <$email>"),
		tags => (),
		version => "0.0.0",
		provides => (),
		depends => (),
	);

	# Create the module skeleton
	mkdir $dir-name;
	chdir $dir-name;
	mkdir "bin";
	mkdir "lib";
	mkdir "t";


my $editorconfig = q:to/EOF/
[*]
charset              = utf8
end_of_line          = lf
insert_final_newline = true
indent_style         = tab

[*.json]
indent_style = space
indent_size  = 2
EOF
;

	# Write some files
	spurt("META6.json", to-json(%meta));

	if ($git) {
		my $gitignore = q:to/EOF/
# Perl 6 precompiled files
.precomp

# Editor files
*~     # emacs
.*.sw? # vim
EOF
		;

		spurt(".gitignore", $gitignore);

		run « git init »;
		run « git add . »;
		run « git commit -m "Initial commit" »;
	}

	say "Created new project folder at {$dir-name.IO.absolute}";
}

multi sub MAIN("pkg", "ebuild", $path where /META6.json$/, Bool :$force = False)
{
	my %meta = from-json(slurp($path));
	my Str $output = make-ebuild(%meta);
	my Str $atom-name = atom-name(%meta<name>, %meta<version>);

	spurt("{$atom-name}.ebuild", $output);

	say "Saved $atom-name";
}

multi sub MAIN("release", $path = ".", Bool :$ask = False)
{
	# Define release types
	my Str @release-types = (
		"Major",
		"Minor",
		"Bugfix",
	);
	my Int $default-release = 3;
	my Str $absolute-path = $path.IO.absolute;

	# Change to the directory to release
	chdir $absolute-path;

	# Make sure the directory is clean
	if ($absolute-path.IO.add(".git").e) {
		my $git-cmd = run « git status --short », :out;

		if (0 < $git-cmd.out.lines.elems) {
			die "Refusing to work on an unclean directory.";
		}
	}

	# Get the META6 info
	my %meta = get-meta();

	say "Making release for {%meta<name>} v{%meta<version>}";

	# Output the possible release types
	say "Release type";

	for @release-types.kv -> $i,  $type {
		say "  {$i + 1} - $type";
	};

	# Request user input to select the release type
	my Int $release;

	loop {
		my $input = prompt "Release type [$default-release]: ";

		if ($input ~~ /^$ | ^\d+$/) {
			$release = $input.Int;
		}

		if ($release == 0) {
			$release = $default-release;
		}

		$release--;

		if ($release < @release-types.elems) {
			last;
		}
	}

	# Update the version accordingly
	my @version = %meta<version>.split(".");
	my @new-version = @version;

	given @release-types[$release].lc {
		when "major"  { 
			@new-version[0]++;
			@new-version[1] = 0;
			@new-version[2] = 0;
		}
		when "minor"  {
			@new-version[1]++;
			@new-version[2] = 0;
		}
		when "bugfix" {
			@new-version[2]++;
		}
	}

	%meta<version> = @new-version.join(".");

	say "New release version will be {%meta<version>}";

	exit if $ask && !confirm;

	put-meta(:%meta);

	# Commit the updated META6
	if ($absolute-path.IO.add(".git").e) {
		run « git add META6.json »;
		run « git commit -m "Bump version to {%meta<version>}" »;
		run « git tag "v{%meta<version>}" »;
	}

	exit if $ask && !confirm("Create new dist?");

	# Build the dist
	MAIN("dist", $absolute-path);
}

multi sub MAIN("touch", "bin", Str $provide)
{
	my %meta = get-meta;
	my $path = "./bin".IO;

	$path = $path.add($provide);

	if ($path.e) {
		die "File already exists at {$path.absolute}";
	}

	mkdir $path.parent.absolute;

	# Create template
	my $template = qq:to/EOF/
#! /usr/bin/env perl6

use v{%meta<perl>};

sub MAIN
\{
	…
\}
EOF
;

	spurt($path.absolute, $template);

	# Update META6.json
	%meta<provides>{$provide} = $path.relative;

	put-meta(:%meta);

	# Inform the user of success
	say "Added $provide to {%meta<name>}";
}

multi sub MAIN("touch", "lib", Str $provide, Str :$type = "")
{
	my %meta = get-meta;
	my $path = "./lib".IO;

	# Deduce the path to create
	for $provide.split("::") {
		$path = $path.add($_);
	}

	$path = $path.extension("pm6", parts => 0);

	if ($path.e) {
		die "File already exists at {$path.absolute}";
	}

	# Create directories if needed
	mkdir $path.parent.absolute;

	# Create template
	my $template = qq:to/EOF/
#! /usr/bin/env false

use v{%meta<perl>};

EOF
;

	given $type {
		when "class" {
			$template ~= "class $provide " ~ '{ … }' ~ "\n";
		}
		when "unit" {
			$template ~= "unit module $provide;\n";
		}
	}

	spurt($path.absolute, $template);

	# Update META6.json
	%meta<provides>{$provide} = $path.relative;

	put-meta(:%meta);

	# Inform the user of success
	say "Added $provide to {%meta<name>}";
}
