#!/usr/bin/env perl

use lib 'auto-lib', 'lib';

use 5.010;
use strict;
use warnings;

use Data::Printer;
use Paws;
use Moose::Util;
use ARGV::Struct;
use Term::ANSIColor 2.00 qw();
use Hash::Flatten qw//;
use List::Util qw(reduce);
use Module::Find;

use Getopt::Long qw/GetOptionsFromArray/;

my @args = @ARGV;

my $aws = Paws->new;

my $service_name = shift @args;
if (not defined $service_name) {
  say "A list of the services you have available";
  say $_ for (sort $aws->available_services);
  exit 1;  
}

my $service = $aws->class_for_service($service_name);

my $opts = {};
my @opts = (
  'caller=s',
  'region=s',
  'debug',
  'help'
);
#if ($service->meta->find_attribute_by_name('region')) {

GetOptionsFromArray(\@args, $opts, @opts);

my $method_name = shift @args;

$service = $aws->service($service_name, %$opts);

my $call;

if (not defined $method_name or not $call = $service->meta->find_method_by_name($method_name)){
  if (defined $method_name) {
    print "Don't know method $method_name on $service_name\n\n";
  } else {
    print "Please specify a method for $service_name\n\n"
  }
  
  print "Maybe you ment:\n";

  map  { say $_ }
    sort 
    map  { $_->name } 
    grep { $_->package_name =~ m/^Paws\:\:/ and 
           $_->name =~ m/^[A-Z]/ 
         } 
    $service->meta->get_all_methods;
  exit 1;
}

die "invalid method" if ($call->package_name !~ m/^Paws\:\:/);

my $help_with_method_call = grep { $_ =~ m/^help$/i } @args;

die "HELP!!!" if ($help_with_method_call);

my %args = %{ ARGV::Struct->new(argv => [ '{', @args, '}' ])->parse };

if ($opts->{ debug }) {
  print "Arguments to the call:\n";
  p %args;
} 

# $call is a Meta Method Object. It can be called via execute
my $result = eval {$call->execute($service, %args) };
if ($@) {
  print $@ if ($opts->{debug});
  if (ref($@) and $@->isa('Moose::Exception::AttributeIsRequired')) {
    print "Call to $method_name requires argument " . $@->attribute_name . "\n";
  } else {
    die $@;
  }

  exit 1;
}

if (ref($result)) {
  my $h = $service->to_hash($result);
  $h = Hash::Flatten::flatten($h, { HashDelimiter => '.', ArrayDelimiter => '.' });

  my $max_chars = reduce { length($a) > length($b) ? $a : $b } keys %$h;
  $max_chars = length($max_chars);
  #TODO: colorize
  say "$_: " . (' ' x ($max_chars - length($_))) .  $h->{ $_ } for (sort keys %$h);
}
