#!/usr/bin/env perl

use Modern::Perl;

use WebService::GoogleAPI::Client;
use Data::Dumper qw (Dumper);
use Data::Dump 'pp';
use Carp;
use URL::Encode qw/url_encode/;


my $config = {
  debug             => 0,
  key               => $ENV{GOOGLE_MAPS_KEY},
  input_address     => url_encode($ARGV[0]) || undef,
  get_nearby_places => 0,
};

###
### VALIDATE CLI PARAMS AND ENV
###
croak(
  'The Geo-coding API requires an API key and cannot be accessed with OAUTH keys - create a key and set $ENV{GOOGLE_MAPS_KEY} - "export GOOGLE_MAPS_KEY=<YOUR_API_KEY>'
) unless defined $ENV{GOOGLE_MAPS_KEY};

croak("you must pass an address as a parameter") unless @ARGV > 0;


=head1 geocoding_api.pl

Perform an address lookup on the CLI paassed parameter - assumes $ENV{GOOGLE_MAPS_KEY}

    perl geocoding_api.pl 'Short Street, Southport, QLD 4215 Australia'

=head2 PRE-REQUISITES


Setup a Google Project in the Google Console and add the Translate API Library. 

An API Key is required with permission to access the GeoCode API and if required the Places API.
  

=head2 OTHER RELATED PERL MODULES

=over 2

=item  L<WWW::Google::Places> 

=back


=head2 RELEVANT GOOGLE API LINKS

=over 2

=item L<https://developers.google.com/places/web-service/search>

=item L<https://console.cloud.google.com/apis/credentials>

=item L<https://developers.google.com/places/web-service/details>

=back 

=cut


####
####
####            SET UP THE CLIENT AS THE DEFAULT USER
####
####
## assumes gapi.json configuration in working directory with scoped project and user authorization
## manunally sets the client user email to be the first in the gapi.json file
my $gapi_client       = WebService::GoogleAPI::Client->new(debug => $config->{debug}, gapi_json => 'gapi.json');
my $aref_token_emails = $gapi_client->auth_storage->get_token_emails_from_storage;
my $user              = $aref_token_emails->[0];    ## default to the first user
$gapi_client->user($user);
say 'x' x 180;
# say $gapi_client->{ua}{credentials}{access_token};
#my $key = $gapi_client->{ua}{credentials}{access_token}; - can't use this :\

####
####
####            GEOCODE ADDRESS PASSED AS PARAMETER USING API KEY
####            AND DISPLAY RESULT(s)
####
## https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY

my $ret = $gapi_client->api_query({
  path    => 'https://maps.googleapis.com/maps/api/geocode/json',    # . $key  ,
  method  => 'GET',
  options => {
    key     => $config->{key},
    address => $config->{input_address},                             # '1600+Amphitheatre+Parkway,+Mountain+View,+CA'
  }
})->json;

if ($ret->{status} eq 'OK') {
  my $latlng = display_place_results_and_return_first_latlng($ret->{results});
  get_nearby_places($gapi_client, $latlng, 'Software') if ($config->{get_nearby_places});


} else {
  say qq{REQUEST NOT OK - $ret->{status} };
}
say 'x' x 180;
exit;


############# HELPER SUBS ###############

sub display_place_results_and_return_first_latlng {
  my ($results) = @_;    ## expects the results list from response->{results}
  my $ret = "";
  foreach my $r (@$results) {
    #say  Dumper $r;
    say qq{$r->{formatted_address}};
    say qq{$r->{geometry}{location}{lat} , $r->{geometry}{location}{lng} };
    $ret = "$r->{geometry}{location}{lat},$r->{geometry}{location}{lng}"
        unless $ret;    ## set return value as string containg first lat,lng pair
  }
  return $ret;
}

sub get_nearby_places {
# https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=1500&type=restaurant&keyword=cruise&key=YOUR_API_KEY
  my ($client, $latlng, $search_term) = @_;

  # place types - why so restrictive?
  # https://developers.google.com/places/web-service/supported_types#table1

  my $resp = $client->api_query({
    path    => 'https://maps.googleapis.com/maps/api/place/nearbysearch/json',    # . $key  ,
    method  => 'GET',
    options => {
      key      => $config->{key},
      location => $latlng,
      keyword  => $search_term,
      radius   => 1500,
      type     => 'establishment',    #'store'
    }
  });
  my $result = $resp->json;
  croak(Dumper $result ) unless $result->{status} eq 'OK';

  foreach my $place (@{ $result->{results} }) {
    say "\n";
    say '--------------------';
    say "Name: $place->{name}";
    say "Types: " . join(',', @{ $place->{types} });
    say "Vicinity $place->{vicinity}";
    say "Location: $place->{geometry}{location}{lat} , $place->{geometry}{location}{lng}";
    say "Rating: $place->{rating}";
    say "Place ID $place->{place_id}";

    get_place_id_detail($client, $place->{place_id});
    say '--------------------';
    #croak('stop 1');
  }
}


sub get_place_id_detail {
  my ($client, $placeid) = @_;
# https://maps.googleapis.com/maps/api/place/details/json?placeid=ChIJN1t_tDeuEmsRUsoyG83frY4&fields=name,rating,formatted_phone_number&key=YOUR_API_KEY
  my $resp = $client->api_query({
    path    => 'https://maps.googleapis.com/maps/api/place/details/json',    # . $key  ,
    method  => 'GET',
    options => {
      placeid => $placeid,
      key     => $config->{key}
    }
  });
  my $result = $resp->json;
  croak(Dumper $result ) unless $result->{status} eq 'OK';
  #say pp $result;
  say "Website: $result->{result}{website}";
  say "Map URL: $result->{result}{url}";
  say "Phone: $result->{result}{formatted_phone_number}";

}
