package Linux::GetPidstat::Writer::Mackerel;
use 5.008001;
use strict;
use warnings;

use Carp;
use Time::Piece;
use WebService::Mackerel;
use JSON::XS qw/decode_json encode_json/;

sub new {
    my ( $class, %opt ) = @_;

    my $mackerel = WebService::Mackerel->new(
        api_key      => $opt{mackerel_api_key},
        service_name => $opt{mackerel_service_name},
    );
    $opt{mackerel} = $mackerel;
    $opt{mackerel_metric_key_prefix} = "" unless defined $opt{mackerel_metric_key_prefix};

    bless \%opt, $class;
}

sub output {
    my ($self, $program_name, $metric_name, $metric) = @_;
    my $graph_name = sprintf("custom.%s%s.%s", $self->{mackerel_metric_key_prefix}, $metric_name, $program_name);

    my $metric_type = $self->{mackerel_metric_type};
    if ($self->{dry_run}) {
        printf "(dry_run) mackerel post: type=%s, name=%s, time=%s, metric=%s\n",
            $metric_type, $graph_name, $self->{now}->epoch, $metric;
        return;
    }

    my $res = do {
        if ($metric_type eq "service") {
            $self->{mackerel}->post_service_metrics([{
                "name"  => $graph_name,
                "time"  => $self->{now}->epoch,
                "value" => $metric,
            }]);
        } elsif ($metric_type eq "host") {
            $self->{mackerel}->post_host_metrics([{
                "hostId" => $self->{mackerel_host_id},
                "name"   => $graph_name,
                "time"   => $self->{now}->epoch,
                "value"  => $metric,
            }]);
        } else {
            croak "Invalid metric type of mackerel: type=$metric_type";
        }
    };

    my $content = eval { decode_json $res; };
    if (chomp $@) {
        carp "Failed mackerel post $metric_type metrics: err=$@, res=$res";
        return;
    }

    my $is_success = $content->{success} || 0;
    if ($is_success != JSON::true or $content->{error}) {
        use Data::Dumper;
        local $Data::Dumper::Terse  = 1;
        local $Data::Dumper::Indent = 0;
        carp "Failed mackerel post $metric_type metrics: res=" . Data::Dumper::Dumper($content);
    }
}

sub bulk_output {
    my ($self, $ret_pidstats) = @_;

    my $metric_type = $self->{mackerel_metric_type};
    my @request_stuffs;
    # ex. backup_mysql => { cpu => 21.0 }
    while (my ($program_name, $s) = each %$ret_pidstats) {
        while (my ($metric_name, $metric) = each %$s) {
            my $graph_name = sprintf("custom.%s%s.%s", $self->{mackerel_metric_key_prefix}, $metric_name, $program_name);
            my %stuff = (
                "name"  => $graph_name,
                "time"  => $self->{now}->epoch,
                "value" => $metric,
                ($metric_type eq "host" ? (hostId => $self->{mackerel_host_id}) : ()),
            );
            push @request_stuffs, \%stuff;
        }
    }

    if ($self->{dry_run}) {
        printf "(dry_run) mackerel post: type=%s, time=%s, metric=%s\n",
            $metric_type, $self->{now}->epoch, encode_json(\@request_stuffs);
        return;
    }

    my $res = do {
        if ($metric_type eq "service") {
            $self->{mackerel}->post_service_metrics(\@request_stuffs)
        } elsif ($metric_type eq "host") {
            $self->{mackerel}->post_host_metrics(\@request_stuffs)
        } else {
            croak "Invalid metric type of mackerel: type=$metric_type";
        }
    };

    my $content = eval { decode_json $res; };
    if (chomp $@) {
        carp "Failed mackerel post $metric_type metrics: err=$@, res=$res";
        return;
    }

    my $is_success = $content->{success} || 0;
    if ($is_success != JSON::true or $content->{error}) {
        use Data::Dumper;
        local $Data::Dumper::Terse  = 1;
        local $Data::Dumper::Indent = 0;
        carp "Failed mackerel post $metric_type metrics: res=" . Data::Dumper::Dumper($content);
    }
}

1;
__END__

=encoding utf-8

=head1 NAME

Linux::GetPidstat::Writer::Mackerel - Write pidstat's results to mackerel

=head1 SYNOPSIS

    use Linux::GetPidstat::Writer::Mackerel;

    my $instance = Linux::GetPidstat::Writer::Mackerel->new(
        mackerel_metric_type  => 'service',
        mackerel_api_key      => 'api_key',
        mackerel_service_name => 'service_name',
        now                   => $t,
        dry_run               => $self->{dry_run},
    );
    $instance->output('backup_mysql', 'cpu', '21.20');

=cut

