package Net::Airbrake;

use strict;
use warnings;

our $VERSION = '0.02';

use HTTP::Tiny;
use JSON qw(decode_json);
use Scope::Guard qw(guard);
use Net::Airbrake::Request;
use Net::Airbrake::Error;

use Class::Tiny {
    api_key     => undef,
    project_id  => undef,
    environment_name => $ENV{PLACK_ENV} || 'development',
    base_url    => "https://airbrake.io",
    _errors     => sub { [] },
    _ua         => sub { HTTP::Tiny->new(agent => "Net-Airbrake/$VERSION", timeout => 5) }
};

sub add_error {
    my $self = shift;
    my ($error) = @_;

    push @{$self->_errors}, Net::Airbrake::Error->new($error);
}

sub has_error {
    scalar @{shift->_errors} ? 1 : 0;
}

sub send {
    my $self = shift;
    my ($option) = @_;

    return unless $self->has_error;

    my $context = {
        os          => $^O,
        language    => "Perl $^V",
        environment => $self->environment_name,
        %{$option->{context} || {}},
    };
    my $req = Net::Airbrake::Request->new({
        errors      => $self->_errors,
        context     => $context,
        environment => $option->{environment} || {},
        session     => $option->{session}     || {},
        params      => $option->{params}      || {},
    });

    my $guard = guard { $self->_errors([]) };
    my $res = $self->_ua->request(POST => $self->_url, {
        content => $req->to_json,
        headers => { 'Content-Type' => 'application/json' },
    });
    die "Request failed to Airbrake: @{[$res->{status}]} @{[$res->{reason}]} (@{[$res->{content}]})"
        unless $res->{success};

    decode_json($res->{content});
}

sub notify {
    my $self = shift;
    my ($error, $option) = @_;

    $self->add_error($error);
    $self->send($option);
}

sub _url {
    my $self = shift;

    $self->base_url . "/api/v3/projects/@{[$self->project_id]}/notices?key=@{[$self->api_key]}";
}

1;
__END__

=pod

=head1 NAME

Net::Airbrake - Airbrake Notifier API V3 Client

=head1 SYNOPSIS

  use Net::Airbrake;

  my $airbrake = Net::Airbrake->new(
      api_key    => 'xxxxxxx',
      project_id => 9999999,
  );

  eval { die 'Oops' };
  $airbrake->notify($@);

=head1 DESCRIPTION

Net::Airbrake is a client of L<Airbrake|https://airbrake.io> Notifier API V3.

=head1 CLASS METHODS

=head2 new(\%param)

Create a new instance.

=over 4

=item api_key

Required. API Key of your project.

=item project_id

Required. Project ID.

=item environment_name

Optional. The name of environment your application is running.
Default value is used $ENV{PLACK_ENV} or 'development'.

=item base_url

Optional. The server base URL to send report.
Default is "https://airbrake.io".

=back

=head1 INSTANCE METHODS

=head2 add_error($error)

Add an error. $error accepts HashRef, Object, string generated by die() or just
string message. If you want to send raw error report, use HashRef included
following key/value pairs:

=over 4

=item type => String

Required. Error type.

=item message => String

Required. Error message.

=item backtrace => ArrayRef[HashRef]

Optional. HashRef can contain followings key/value pairs:

=over 8

=item file => String

File name an error occurred.

=item line => Integer

Line number an error occurred.

=item function => String

Subroutine name an error occurred.

=back

=back

=head2 has_error()

Return true value if the instance has been added error by add_error().

=head2 send(\%option)

Send errors added by add_error() to Airbrake. \%option parameter is optional and
all key/value pairs of its also optional. You can specify followings to report
 error details.

details

=over 4

=item context => HashRef

Context values of its error.

=item environment => HashRef

Environment variables. Set HTTP Headers on web application as usual.

=item session => HashRef

Session values. Set your application session parameters.

=item params => HashRef

Request parameters. Set HTTP Request parameters on web application as usual.

=back

=head2 notify(\%error, \%option)

Shortcut of add_error() and send() combination.

=head1 SEE ALSO

Notifier API V3 - L<https://help.airbrake.io/kb/api-2/notifier-api-v3>

=head1 AUTHOR

Six Apart, Ltd. E<lt>sixapart@cpan.orgE<gt>

=head1 LICENSE

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut
