#!perl6


use Sparrowdo;

use Sparrowdo::Ssh;

use Sparrowdo::Docker;

use Sparrowdo::Localhost;

use Sparrowdo::Utils;

use Sparrow6::DSL;

sub MAIN (

  Str  :$host = '127.0.0.1', 
  Str  :$sparrowfile, 
  Str  :$tags, 
  Str  :$repo = "http://rakudist.raku.org/repo/", 
  Str  :$ssh_user, 
  Int  :$ssh_port = 22, 
  Str  :$ssh_private_key, 
  Bool :$verbose = False,
  Bool :$dry_run = False,
  Bool :$debug   = False,
  Bool :$bootstrap = False, 
  Bool :$no_sudo = False,
  Bool :$localhost = False,
  Str  :$docker,
  Str  :$conf,
  Str  :$prefix,
  Str  :$sync,
  Bool :$no_index_update  = False,
)

{


  my $spf = $sparrowfile || 'sparrowfile'; # Sparrowfile to run

  if $conf && ! ( $conf.IO ~~ :e ) {
    die "configuration file $conf does not exist";
  }

  my $path-to-config = $conf || "config.pl6";

  generate-sparrowdo-harness %(
    config => $path-to-config,
    sparrowfile => $spf,
    ssh-user => $ssh_user,
    sync => $sync,
    verbose => $verbose,
    sudo => ! $no_sudo,
    debug => $debug,
    repo => $repo,
    prefix => $prefix,
    index-update => ! $no_index_update,
    tags => $tags,
    type => $docker ?? "docker" !! "default",
    localhost => $localhost,
  ) unless $host.IO ~~ :f;

  if ($docker) {

    prepare-docker-host(
      $docker,
      %( 
        verbose => $verbose,
        prefix  => $prefix,
      )
    );

    if $bootstrap {
      bootstrap-docker-host(
        $docker,
        %( 
            verbose => $verbose, 
            prefix  => $prefix 
         )
      );
      if ! $sparrowfile && ! $spf.IO.e  { 
        # don't try to run sparrowfile if in bootstrap mode
        # and if sparrowfile is not passed and 
        # default sparrowfile does not exist
        say "Congratulations!\nYour system is ready to be configured automatically using Sparrowdo!";
        exit 0;
      }
    }

    die "sparrowfile $spf does not exit" unless $spf.IO ~~ :e;

    run-tasks-docker-host(
      $docker, 
      %( 
        verbose => $verbose, 
        prefix  => $prefix 
      )
    );

  } elsif $localhost {  


    if $bootstrap {
      bootstrap-localhost %( 
        verbose => $verbose 
      );
      if ! $sparrowfile && ! $spf.IO.e  { 
        # don't try to run sparrowfile if in bootstrap mode
        # and if sparrowfile is not passed and 
        # default sparrowfile does not exist
        say "Congratulations!\nYour system is ready to be configured automatically using Sparrowdo!";
        exit 0;
      }
    }

    die "sparrowfile $spf does not exit" unless $spf.IO ~~ :e;

    run-tasks-localhost %( 
      verbose => $verbose, 
    );

  } elsif $host.IO ~~ :f {  

    prepare-sparrowdo-files %( 
      verbose => $verbose
    );


    my @hosts = EVALFILE($host);

    my %tags = $tags ?? parse-tags($tags) !! %(); 

    say "cli tags: {%tags.perl}" if $verbose;

    my @required-tags = %tags.keys.grep({ %tags{$_}.isa(Bool) });

    say "required tags: {@required-tags.perl}" if $verbose;

    for @hosts -> $i {

      my $h;

      my $host-tags;

      if $i.isa("Hash") {
        $h = $i<host>;
        $host-tags = $i<tags> if $i<tags>;
      } else {
        $h = $i;
      }

     my %host-tags = $host-tags ?? parse-tags($host-tags) !! %();

     # if --tags is passed
     # filter hosts by tags

     my $tag-pass = False;
 
     if @required-tags {

        $tag-pass = False;

        for @required-tags -> $tg {
          if %host-tags{$tg}:exists {
            $tag-pass = True;
          } else {
            $tag-pass = False;
            last;
          }
        }

      } else {

        $tag-pass = True

      }

      if $tag-pass {
        say "ALLOW host {$h} by tags creteria" if $verbose;
      } else {
        say "SKIP host {$h} by tags creteria" if $verbose;
        next;
      }


      next if $dry_run;

      my $worker-id = (^3).pick + 1;
  
      my $sparky-project-dir = %*ENV<SPARKY_ROOT> ??  "{%*ENV<SPARKY_ROOT>}/worker{$worker-id}" !! "{%*ENV<HOME>}/.sparky/projects/worker{$worker-id}";
  
      mkdir "{$sparky-project-dir}/.triggers" unless "{$sparky-project-dir}/.triggers".IO ~~ :d;
  
      spurt "{$sparky-project-dir}/sparrowfile", "# dummy file, generated by sparrowdo";

      my $rand = ('a' .. 'z').pick(20).join('');

      my $id = "{$rand}{$*PID}";

      my $cache-dir = %*ENV<SPARKY_ROOT> ??  "{%*ENV<SPARKY_ROOT>}/.cache/$id/" !! "{%*ENV<HOME>}/.sparky/.cache/$id/";

      mkdir $cache-dir;

      if $verbose {
        shell("cp -rv .sparrowdo/* $cache-dir");
        if $spf.IO ~~ :e {
          shell("cp -v $spf $cache-dir/sparrowfile");
        }
      } else {
        shell("cp -r .sparrowdo/* $cache-dir");
        if $spf.IO ~~ :e {
          shell("cp $spf $cache-dir/sparrowfile");
        }
      }

      my %sparrowdo-config = %(
          repo => $repo,
          verbose => $verbose,
          bootstrap => $bootstrap,
          no_index_update => $no_index_update
      );

      my @effective-tags;

      push @effective-tags, $host-tags if $host-tags;
      push @effective-tags, $tags if $tags;

      if @effective-tags.elems {
        %sparrowdo-config<tags> = @effective-tags.join(",");
      }

      %sparrowdo-config<conf> = $path-to-config if $path-to-config.IO ~~ :e;

      my %trigger = %(
        cwd => $cache-dir,
      );

      if $h ~~ /^^ \s* 'docker:' (\S+)/ {
        %sparrowdo-config<docker> = "$0";  
        %sparrowdo-config<no_sudo> = True;  
        %trigger<description> = %host-tags<name> ?? "docker [{%host-tags<name>}]" !! "docker [$0]"
      } elsif $h eq "localhost" {
        %trigger<description> =  %host-tags<name> ?? "localhost [{%host-tags<name>}]" !! "[localhost]";
        %sparrowdo-config<no_sudo> = $no_sudo;  
      } else {
        %sparrowdo-config<host> = $h;  
        %sparrowdo-config<ssh_port> = $ssh_port if $ssh_port;  
        %sparrowdo-config<ssh_user> = $ssh_user if $ssh_user;  
        %sparrowdo-config<ssh_private_key> = $ssh_private_key if $ssh_private_key;  
        %sparrowdo-config<no_sudo> = $no_sudo;  
        %trigger<description> =  %host-tags<name> ?? "host [{%host-tags<name>}]" !! "host [$h]"
      }

      %trigger<sparrowdo> = %sparrowdo-config;

      spurt "{$sparky-project-dir}/.triggers/$id", %trigger.perl;

      say "queue build for [$h] on [worker-{$worker-id}]";

    }

  } else {  

    prepare-ssh-host(
      $host,
      %( 
        ssh-user => $ssh_user,
        ssh-port => $ssh_port,
        ssh-private-key => $ssh_private_key,
        verbose => $verbose,
        sync    => $sync,
        prefix  => $prefix 

      )
    );

    if $bootstrap {
      bootstrap-ssh-host(
        $host,
        %( 
          verbose   => $verbose, 
          ssh-user  => $ssh_user, 
          ssh-port  => $ssh_port,
          ssh-private-key => $ssh_private_key,
          prefix    => $prefix 
        )    
      );
      if ! $sparrowfile && ! $spf.IO.e  { 
        # don't try to run sparrowfile if in bootstrap mode
        # and if sparrowfile is not passed and 
        # default sparrowfile does not exist
        say "Congratulations!\nYour system is ready to be configured automatically using Sparrowdo!";
        exit 0;
      }
    }

    die "sparrowfile $spf does not exit" unless $spf.IO ~~ :e;

    run-tasks-ssh-host(
      $host,$spf,
      %( 
        ssh-user => $ssh_user,
        ssh-port => $ssh_port,
        ssh-private-key => $ssh_private_key,
        verbose  => $verbose, 
        prefix   => $prefix 
      )
    );
  }

}

