# Copyright 2019, Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# The class representing the exception message from Google Ads API server.

package Google::Ads::GoogleAds::GoogleAdsException;

use strict;
use warnings;
use version;

# The following needs to be on one line because CPAN uses a particularly hacky
# eval() to determine module versions.
use Google::Ads::GoogleAds::Constants; our $VERSION = ${Google::Ads::GoogleAds::Constants::VERSION};

use Class::Std::Fast constructor => 'none';

# Class::Std-style attributes. Most values are read from googleads.properties file.
# These need to go in the same line for older Perl interpreters to understand.
my %code_of : ATTR(:get<code> :default<>);
my %message_of : ATTR(:get<message> :default<>);
my %status_of : ATTR(:get<status> :default<>);
my %details_of : ATTR(:get<details> :default<>);

sub new {
  my $self  = bless \do { my $exception = Class::Std::Fast::ID }, shift;
  my $ident = ident $self;

  my $response_body = shift;
  my $error         = $response_body->{error};

  $code_of{$ident}    = $error->{code};
  $message_of{$ident} = $error->{message};
  $status_of{$ident}  = $error->{status};

  # The details may contain GoogleAdsFailure or standard GRPC errors, e.g.
  # BadRequest, PreconditionFailure, QuotaFailure.
  $details_of{$ident} = $error->{details};

  return $self;
}

# Extracts the GoogleAdsFailure object from the details hash.
sub get_google_ads_failure {
  my ($self) = @_;

  foreach my $detail (@{$self->get_details}) {
    my $type = $detail->{"\@type"};
    if ($type =~ /google.ads.googleads.v(\d+).errors.GoogleAdsFailure/) {
      my $class =
        sprintf
        (Google::Ads::GoogleAds::Constants::GOOGLE_ADS_FAILURE_CLASS_NAME,
        $1);

      # Require class name.
      eval("require $class");
      return $class->new({errors => $detail->{errors}});
    }
  }
  return undef;
}

1;

=pod

=head1 NAME

Google::Ads::GoogleAds::GoogleAdsException

=head1 SYNOPSIS

  my $api_client = Google::Ads::GoogleAds::Client->new();
  $api_client->set_die_on_faults(0);

  my $response = $api_client->AdGroupAdService()->mutate($mutate_request);

  if ($response->isa("Google::Ads::GoogleAds::GoogleAdsException")) {
    my $google_ads_failure = $response->get_google_ads_failure();

    # Do something with thie GoogleAdsFailure object.
  }

=head1 DESCRIPTION

The class representing the exception message from Google Ads API server.

=head1 ATTRIBUTES

There is a get_ method associated with each attribute for retrieving them dynamically.

=head2 code

The HTTP response code.

=head2 message

A human-readable description of this exception.

=head2 status

The status code of this exception.

=head2 details

The details information of this exception, which may contains failure messages.

=head1 METHODS

=head2 get_google_ads_failure

Extracts a L<Google::Ads::GoogleAds::VX::Errors::GoogleAdsFailure> object from the
L</details> attribute of the current exception object.

=head3 Returns

A L<Google::Ads::GoogleAds::VX::Errors::GoogleAdsFailure> object or undef if not found.

=cut
