use Zef::Configuration;
my $zc-id :="Zef Configuration Manager v0.0.11";

my constant ZC = Zef::Configuration;

my %*SUB-MAIN-OPTS = :named-anywhere;

sub io-from-path($path) {
    $path ?? $path.IO !! ZC.user-configuration
}

sub writeable-io-from-path($path is copy) {
    $path = io-from-path($path);
    ZC.is-configuration-writeable($path)
      ?? $path
      !! ZC.new-user-configuration
}

sub meh($message) {
    note $message;
    exit 1;
}

sub overview($zc, $config) {
    qq:to/MESSAGE/
    $zc-id
    -- from $config --
    $zc.status()
    MESSAGE
}

sub object-from-tag($zc, $tag) {
    with $zc.object-from-tag($tag) -> \object {
        object ~~ List
          ?? meh "'$tag' Matched multiple times, select full tag-name:\n  {
                 object.map({ .key ~ '-' ~ $tag }).join(', ');
             }"
          !! object
    }
    else {
        meh "'$tag' unknown";
    }
}

sub set-enabled($path, $tag, $state, $dry-run) {
    my $io := writeable-io-from-path $path;
    my $zc := $io.e ?? ZC.new($io) !! ZC.new;
    my $object := object-from-tag $zc, $tag;
    meh "'$tag' already { $state ?? 'en' !! 'dis' }abled"
      if $object.enabled == $state;

    $object.enabled = $state;
    say "** { $state ?? 'En' !! 'Dis' }abled '$tag' in:";
    say "** $io\n----------------------------------------------";
    $io.spurt: $zc.json unless $dry-run;
    say $zc.group-status($object);
}

multi sub MAIN(:$config-path) {
#= Show information
    my $io := io-from-path($config-path);
    say overview
      ZC.new($io),
      ($config-path ?? $io !! 'default config')
        ~ (" (READ-ONLY)" unless ZC.is-configuration-writeable($io));
    say $*USAGE;
}

multi sub MAIN("reset",
  :config-path($path), Bool :$dry-run
) {
#= Reset to factory settings
    my $zc := ZC.new;
    my $io := writeable-io-from-path $path;
    $io.spurt: $zc.json unless $dry-run;
    say "** Configuration reset to factory settings in:";
    say "** $io\n----------------------------------------------";
    say $zc.status;
}

multi sub MAIN("enable", $tag,
  :config-path($path), Bool :$dry-run
) {
#= Enable an item in the configuration
    set-enabled $path, $tag, True, $dry-run;
}

multi sub MAIN("disable", $tag,
  :config-path($path), Bool :$dry-run
) {
#= Disable an item in the configuration
    set-enabled $path, $tag, False, $dry-run;
}

multi sub MAIN("add-repository",
       $tag,
       $repo-url,
       :$name = $tag,
       :config-path($path),
  Bool :$dry-run
) {
#= Add a repository at the beginning of the chain
    my $io := writeable-io-from-path $path;
    my $zc := $io.e ?? ZC.new($io) !! ZC.new;

    meh "There is already an object with '$tag' in this configuration"
      if $zc.object-from-tag: $tag;

    my $repo := Zef::Configuration::Repository.new:
      :short-name($tag), :$name, :mirrors($repo-url);

    $zc.Repository.unshift:
      Zef::Configuration::RepositoryGroup.new: repositories => $repo;

    $io.spurt: $zc.json unless $dry-run;
    say $zc.group-status($repo);
}

multi sub MAIN("remove-repository",
       $tag,
       :config-path($path),
  Bool :$dry-run
) {
#= Remove a repository
    my $io := writeable-io-from-path $path;
    my $zc := $io.e ?? ZC.new($io) !! ZC.new;

    my $repo := object-from-tag $zc, $tag;  # dies if fails
    $zc.Repository .= grep: -> $group {
        $group.repositories .= grep: *.short-name ne $tag;
    }
    $io.spurt: $zc.json unless $dry-run;
    say "** Removed repository $tag ($repo.name())";
}

use shorten-sub-commands:ver<0.0.8+>:auth<zef:lizmat> &MAIN;

# vim: expandtab shiftwidth=4
