package CloudDeploy::CommandLine::History {
  use MooseX::App;
  use ARGV::Struct;
  use CloudDeploy::Utils;
  use CloudDeploy::DeploymentCollection;
  use Text::ASCIITable;
  use Data::Printer;
  use Term::ANSIColor;

  option include_common => (
    is => 'ro',
    isa => 'Bool',
    documentation => 'Include common parameters when inspecting',
    default => 0,
  );

  option include_attached => (
    is => 'ro',
    isa => 'Bool',
    documentation => 'Include parameters generated by attachments when inspecting',
    default => 0,
  );

  option limit => (
    is => 'ro',
    isa => 'Int',
    documentation => 'Limit listing length',
    default => 10,
  );

  parameter subcommand => (
    is => 'ro',
    isa => 'Str',
    documentation => 'list / search / inspect',
    default => 'list',
  );

  has find_args => (
    is => 'ro',
    isa => 'HashRef',
    lazy => 1,
    default => sub {
      my $self = shift;
      my $args = ARGV::Struct->new(argv => [ '{', @{ $self->extra_argv }, '}' ])->parse;
      return { map { lc($_) => $args->{ $_ } } keys(%$args) };
    }
  );

  sub run {
    my ($self) = @_;

    my $deployments = CloudDeploy::DeploymentCollection->new(account => $ENV{'CPSD_AWS_ACCOUNT'});

    if ($self->subcommand eq 'search') {
      search_deployments($self, $deployments);
    }
    elsif ($self->subcommand eq 'inspect') {
      inspect_deployments($self, $deployments);
    }
    else {
      list_deployments($self, $deployments);
    }
  }

  sub list_deployments {
    my ($self, $deploys) = @_;

    my @list = $deploys->last_log_deployments($self->limit);

    my $table = Text::ASCIITable->new;
    $table->setCols(qw(Timestamp Status Name));

    foreach my $dep (uniq(@list)) {
      $table->addRow(@{ $dep });
    }

    print $table;
  }

  sub search_deployments {
    my ($self, $deploys) = @_;

    # Allow regex in string arguments and MongoDB operators
    foreach my $arg (keys %{ $self->find_args }) {
      my $value = $self->find_args->{ $arg };
      $self->find_args->{ $arg } = qr/$value/i unless (ref $value eq 'HASH');
    }

    my @list = $deploys->search_log_deployments($self->find_args, $self->limit);

    my $table = Text::ASCIITable->new;
    $table->setCols(qw(Timestamp Status Name));

    foreach my $dep (uniq(@list)) {
      $table->addRow(@{ $dep });
    }

    print $table;
  }

  sub inspect_deployments {
    my ($self, $deploys) = @_;

    die "Error: deployment name required!\n" unless (defined $self->find_args->{name});

    unless (defined $self->find_args->{timestamp}) {
       my @list = $deploys->search_log_deployments($self->find_args, 1);
       $self->find_args->{timestamp} = $list[0]->[0];
    }

    my $name = $self->find_args->{name};
    my $timestamp = $self->find_args->{timestamp};
    my $dep = $deploys->get_old_deployment($name, $timestamp);

    die "Error: deployment does not exist!\n" unless (defined $dep);

    # Load class from deployment
    my $module;
    eval {
      $module = load_class($dep->type);
    };
    $module = undef if ($@);

    my $params = $dep->params;

    if (defined $module) {

      # Find params generated from attachment
      unless ($self->include_attached) {
        my @attached =
          map { $_->name }
          grep { $_->does('Attached') }
          $module->{params_class}->meta->get_all_attributes;

        # Remove attached params
        delete $params->{$_} for (@attached);
      }

      # Remove common params
      unless ($self->include_common) {
        my @common_args = ('account', 'ami', 'os_family', 'template', 'devel', 'onlysnapshot', 'update');
        delete $params->{$_} for (@common_args);
      }

    }

    # Remove undefined params
    my @undefined = grep { not defined $params->{$_} } keys(%{ $params });
    delete $params->{$_} for (@undefined);

    print_inspect_output($module, $dep, $params);
  }

  sub print_inspect_output {
    my ($mod, $obj, $par) = @_;

    print "\nTYPE:\n";
    p $obj->type;
    print "\nPARAMS:\n";

    print color('bold yellow'),
          "WARNING: class " . $obj->type . " not found! All parameters are being displayed.\n\n",
          color('reset')
    unless (defined $mod);

    p $par;
    print "\nOUTPUTS:\n";
    p $obj->outputs;

    print "\nCOMMENTS:\n";
    p $obj->comments;

    print "\nCOMMAND LINE (" . $obj->timestamp . "):\n";
    my $command = "clouddeploy deploy";

    if (defined $mod) {
      my @classes = $mod->{class}->meta->superclasses;
      $command = "imager make_ami" if (grep { /MakeAMIBase/ } @classes);
    }
    else {
      print color('bold yellow'),
            "WARNING: class " . $obj->type . " not found! Cannot find if this is an AMI or infrastructure.\n",
            color('reset');
      $command = color('bold red') . "Class missing" . color('clear');
    }

    $command .= " " . $obj->type . ".pm --";

    foreach my $p (keys %{ $par }) {
      $command .= " --$p '" . $par->{$p} . "'";
    }

    print color('bold white'), "\n$command\n\n", color('clear');
  }

  # Temporary fix for duplicates in deployment log collection
  sub uniq {
    my %seen;
    grep !$seen{$_->[0] . $_->[1]}++, @_;
  }
}

1;

