package Amazon::API::ModuleNames;

use strict;
use warnings;

use CLI::Simple::Utils qw(slurp_json);
use CLI::Simple::Constants qw(:booleans);
use Cwd qw(getcwd);

use English qw(-no_match_vars);
use Storable;
use Data::Dumper;
use Amazon::API::Botocore qw(fetch_boto_services %BOTO_SERVICES);
use JSON;

use parent qw(CLI::Simple);

__PACKAGE__->use_log4perl( loglevel => 'info' );

caller or exit __PACKAGE__->main();

########################################################################
sub init {
########################################################################
  my ($self) = @_;

  return;
}

########################################################################
sub cmd_create_module_names {
########################################################################
  my ($self) = @_;

  my $path = $self->get_path // getcwd;

  my $botocore_path = $self->get_boto_path // sprintf '%s/botocore', getcwd;

  die sprintf "ERROR: %s does not contain botocore data\n"
    if !-d $botocore_path || !-r sprintf '%s/botocore/data/ec2/2016-11-15/service-2.json', $botocore_path;

  my $module_names_file = sprintf '%s/module_names.json',     $path;
  my $metadata_file     = sprintf '%s/botocore-metadata.api', $path;

  my $canonical_names = slurp_json($module_names_file);

  if ( -e $metadata_file ) {
    %BOTO_SERVICES = %{ retrieve $metadata_file };
  }
  else {
    fetch_boto_services( $botocore_path, $TRUE );  # fetches metadata when second arg is true
  }

  my %module_names;

  foreach my $service ( keys %BOTO_SERVICES ) {
    my $metadata   = $BOTO_SERVICES{$service}->{metadata}{metadata};
    my $service_id = $metadata->{serviceId};
    my $cname      = $canonical_names->{$service}->{module_name};

    if ( !$cname ) {
      $self->get_logger->info( sprintf 'new service found: %s', $service );

      $cname = $module_names{$service} = $service_id;
      $canonical_names->{$service} = { module_name => $cname, auto_generated => \1 };

      my @parts = split /[\- ]/, $service_id;

      if ( @parts != 1 || $parts[0] !~ /^[A-Z]/xsm ) {
        if ( @parts == 1 ) {
          $cname = $module_names{$service} = length $parts[0] > 3 ? ucfirst $parts[0] : uc $parts[0];
          $canonical_names->{$service}->{module_name} = $cname;
        }
        else {
          $cname = $module_names{$service} = join q{}, map { ucfirst $_ } @parts;
          $canonical_names->{$service}->{module_name} = $cname;
        }
      }
    }

    my $perl_module_name = sprintf 'Amazon::API::%s', $cname;
    $self->get_logger->info( sprintf '%s => %s', $service, $perl_module_name );

    $BOTO_SERVICES{$service}->{metadata} = {
      metadata => {
        serviceId        => $service_id,
        perl_module_name => $perl_module_name,
      }
    };
  }

  $self->get_logger->info( sprintf 'saving %s...', $module_names_file );

  open my $fh, '>', $module_names_file
    or die sprintf 'ERROR: could not open %s for writing: %s', $module_names_file, $OS_ERROR;

  print {$fh} JSON->new->pretty->encode($canonical_names);

  close $fh;

  $self->get_logger->info( sprintf 'storing %s...', $metadata_file );
  store \%BOTO_SERVICES, $metadata_file;

  return $SUCCESS;
}

########################################################################
sub main {
########################################################################
  my @option_specs = qw(
    help|h
    boto-path|b=s
    path|p=s
    loglevel|l=s
    dryrun|d
  );

  return __PACKAGE__->new(
    commands => {
      'create-module-names' => \&cmd_create_module_names,
      'update-module-names' => \&cmd_create_module_names,
    },
    option_specs  => \@option_specs,
    abbreviations => $TRUE,
  )->run;
}

1;
