package Amazon::API::Botocore::Services;

use strict;
use warnings;

use Amazon::API::Botocore qw(fetch_boto_services %BOTO_SERVICES);
use CLI::Simple::Constants qw(:booleans);
use CLI::Simple::Utils qw(slurp_json choose);
use Cwd qw(abs_path);
use Data::Dumper;
use English qw(-no_match_vars);
use JSON qw(decode_json encode_json);
use Pod::Usage;
use Storable qw(nstore);

our $VERSION = '2.4.6';

our %SERVICE_PROTOCOL;

our %SERVICE_CONTENT_TYPES = (
  'json'      => 'application/x-amz-json',
  'rest-json' => 'application/json',
  'rest-xml'  => 'application/xml',
  'query'     => 'application/x-www-form-urlencoded',
  'ec2'       => 'application/x-www-form-urlencoded',
);

use parent qw(CLI::Simple);

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

caller or exit __PACKAGE__->main();

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

  return;
}

########################################################################
sub _check_path {
########################################################################
  my ($path) = @_;

  my $abs_path = abs_path($path);

  return $abs_path
    if -d "$abs_path/.git" && -d "$abs_path/botocore";

  $abs_path = "../$path";

  return $abs_path
    if -d "$abs_path/.git" && -d "$abs_path/botocore";

  die abs_path($path) . " does not point to the Botocore repo\n";
}

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

  my ($service) = $self->get_args;

  my $boto_path = $self->get_boto_path;

  die "ERROR: usage: build-boto-services -p botocore-path list-services [service]\n"
    if !$boto_path;

  $boto_path = _check_path($boto_path);

  fetch_boto_services($boto_path);

  if ($service) {
    print {*STDOUT} JSON->new->pretty->encode( $BOTO_SERVICES{$service} );
  }
  else {
    print {*STDOUT} JSON->new->pretty->encode( \%BOTO_SERVICES );
  }

  return $SUCCESS;
}

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

  my $boto_path = _check_path( $self->get_boto_path );

  fetch_boto_services($boto_path);

  my $output = $self->get_output // 'service-types.api';

  my $limit = $self->get_limit // scalar keys %BOTO_SERVICES;
  my $count = 0;

  foreach my $s ( sort keys %BOTO_SERVICES ) {
    last if !$limit;

    my $path = join q{/}, @{ $BOTO_SERVICES{$s}->{path} };

    my $service  = slurp_json($path);
    my $metadata = $service->{metadata};

    my $protocol    = $metadata->{protocol};
    my $protocols   = $metadata->{protocols} // [$protocol];
    my $jsonVersion = $metadata->{jsonVersion};

    $limit--;

    $self->get_logger->info( sprintf '%s - (%s/%s)', $path, ++$count, scalar keys %BOTO_SERVICES );

    foreach my $protocol ( @{$protocols} ) {
      next if !exists $SERVICE_CONTENT_TYPES{$protocol};

      my $content_type = $SERVICE_CONTENT_TYPES{$protocol};

      if ( $protocol eq 'json' && $jsonVersion ) {
        $content_type = sprintf '%s-%s', $content_type, $jsonVersion;
      }

      $SERVICE_PROTOCOL{$s} = $content_type;

      last;
    }
  }

  nstore(
    { service_protocol => \%SERVICE_PROTOCOL,
      content_types    => \%SERVICE_CONTENT_TYPES,
    },
    $output
  );

  return $SUCCESS;
}

########################################################################
sub main {
########################################################################
  my @option_specs = qw(
    help|h
    boto-path|p=s
    output|o=s
    limit|l=i
  );

  my %commands = (
    'build-services' => \&cmd_build_services,
    'list-services'  => \&cmd_list_services,
    'default'        => \&cmd_build_services,
  );

  return __PACKAGE__->new(
    commands      => \%commands,
    option_specs  => \@option_specs,
    abbreviations => $TRUE,
  )->run;
}

1;

## no critic

__END__

=pod

=head1 NAME

build-boto-services - creates the service.api file containing Botocore metadata

=head1 USAGE

 build-boto-services options command

=head2 Commands

 build-services    creates the services.api binary (default if no command provide)
 list-services     outputs a JSON object describe Botocore services
 
=head2 Options

 --help, -h
 --boto-path, -p 
 --output, -o     Fully qualified output path (default: ./service.api)
 --limit, -l      Number of services to process (default: all) 

=head2 Notes

This script is primarily used to produce a binary version of the Botocore
service metadata. It is used by C<Amazon::API> to determine the content
type of the various Botocore services.

You must have the Botocore project checkout out in some directory.

 build-boto-services -p path/to/botocore-repo -o services.api

=cut
