#!/usr/bin/env perl

use strict;
use warnings;

use Amazon::API::Botocore qw(fetch_boto_services %BOTO_SERVICES);
use Cwd qw(abs_path);

use Data::Dumper;
use English qw(-no_match_vars);
use Getopt::Long qw(:config no_ignore_case);
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',
);

########################################################################
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 main {
########################################################################
  my %options;

  my @options_spec = qw(
    help|h
    boto-path|p=s
    output|o=s
    limit|l=i
  );

  GetOptions( \%options, @options_spec );

  if ( $options{help} ) {
    pod2usage(
      { -verbose  => 99,
        -sections => 'USAGE',
        -exitval  => 1
      }
    );
  }

  my $boto_path = _check_path( $options{'boto-path'} );

  fetch_boto_services($boto_path);

  my $output = $options{output} //= 'service-types.api';

  my $limit = $options{limit} // scalar keys %BOTO_SERVICES;

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

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

    local $RS = undef;

    open my $fh, '<', $path
      or die "could not open $path\n";

    my $service  = decode_json(<$fh>);
    my $metadata = $service->{metadata};

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

    $limit--;

    print {*STDERR} "$path - ($limit remaining)\n";

    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;
    }

    close $fh;
  }

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

  return 0;
}

exit main();

__END__

=pod

=head1 NAME

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

=head1 USAGE

 build-boto-serivces.pl options

=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 used to produce a binary version of the Botocore
service metadata. It is used by 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.pl -p path/to/botocore-repo -o services.api

=cut
