package App::EventStreamr::Status;
use Method::Signatures;
use JSON;
use Scalar::Util::Reftype;
use Moo;
use namespace::clean;

# ABSTRACT: A status object

our $VERSION = '0.5'; # VERSION: Generated by DZP::OurPkg:Version


#my $ConfigRef = sub {
#  croak "config isn't a 'App::EventStreamr::Config' object!" unless reftype( $_[0] )->class eq "App::EventStreamr::Config";
#};

has 'status'      => ( is => 'rw' );
has 'config'      => ( is => 'rw' );

method starting($id,$type) {
  # TODO: Logging here once log role exists
  $self->{status}{$id}{runcount} = $self->{status}{$id}{runcount} ? $self->{status}{$id}{runcount} + 1 : 1;
  $self->{status}{$id}{running} = 0;
  $self->{status}{$id}{status} = "starting";
  $self->{status}{$id}{state} = "soft";
  $self->{status}{$id}{type} = $type;
  $self->{status}{$id}{id} = $id;
  $self->post_status();
}

method waiting($id,$type,$status) {
  # TODO: Logging here once log role exists
  $self->{status}{$id}{status} = $status;
  $self->{status}{$id}{state} = "wait";
  $self->{status}{$id}{type} = $type;
  $self->{status}{$id}{id} = $id;
  $self->post_status();
}

method stopping($id,$type) {
  # TODO: Logging here once log role exists
  $self->{status}{$id}{status} = "stopping";
  $self->{status}{$id}{state} = "soft";
  $self->{status}{$id}{type} = $type;
  $self->{status}{$id}{id} = $id;
  $self->post_status();
}

method restarting($id,$type) {
  # TODO: Logging here once log role exists
  $self->{status}{$id}{status} = "restarting";
  $self->{status}{$id}{state} = "soft";
  $self->{status}{$id}{type} = $type;
  $self->{status}{$id}{id} = $id;
  $self->post_status();
}

method set_state($state,$id,$type) {
  if (defined $self->{status}{$id}{running} &&
      $self->{status}{$id}{running} != $state) {
    # TODO: Logging here once log role exists
    $self->{status}{$id}{runcount} = 0;
    $self->{status}{$id}{running} = $state;
    $self->{status}{$id}{status} = $state ? 'started' : 'stopped';
    $self->{status}{$id}{state} = "hard";
    $self->{status}{$id}{timestamp} = time;
    $self->{status}{$id}{type} = $type;
    $self->{status}{$id}{id} = $id;
    $self->post_status();
    return 1;
  }
  return 0;
}

method threshold($id,$type,$status = "failed") {
  $self->{status}{$id}{timestamp} = time if (! $self->{status}{$id}{timestamp});
  my $age = time - $self->{status}{$id}{timestamp};
  if ( defined $self->{status}{$id}{runcount} && 
  ($self->{status}{$id}{runcount} > 5 && (time % 10) != 0) ) {
    $self->{status}{$id}{status} = $status;
    $self->{status}{$id}{state} = "hard";
    $self->{status}{$id}{type} = $type;
    $self->{status}{$id}{id} = $id;
    $self->info("$id failed to start (count=".$self->{status}{$id}{runcount}.", died=$age secs ago)");
    $self->post_status();
    return 1;
  }
  return 0;
}

method post_status {
  if ($self->config) {
    my $status;
    $status->{status} = $self->{status};
    $status->{macaddress} = $self->config->macaddress;
    $status->{nickname} = $self->config->nickname;

    my $json = to_json($status);
    my %post_data = (
      content => $json,
      'content-type' => 'application/json',
      'content-length' => length($json),
    );
    my $post = $self->config->http->post(
      "http://".$self->config->{mixer}{host}.":3000/status/".$self->config->macaddress,
      \%post_data,
    );

    $self->debug("Status posted to http://".$self->config->{mixer}{host}.":3000/status/".$self->config->macaddress);
    $self->debug({filter => \&Data::Dumper::Dumper,
                  value  => $post}) if ($self->is_debug());

    if ( $self->config->controller ) {
      # The Frontend doesn't like empty objects..
      # TODO: Fix the frontend
      foreach my $key (keys %{$self->{status}}) {
        if (! defined $self->{status}{$key}{id}) {
          delete $self->{status}{$key};
        }
      }

      my $data;
      $data->{key} = "status";
      $data->{value} = $self->{status};

      %post_data = (
        content => to_json($data),
        headers => {
          'station-mgr' => 1,
          'Content-Type' => 'application/json',
        }
      );

      $post = $self->config->http->post(
        $self->config->controller."/api/station/".$self->config->macaddress."/partial", 
        \%post_data,
      );

      $self->debug({filter => \&Data::Dumper::Dumper,
                    value  => $post}) if ($self->is_debug());

      $self->info("Status posted to ".$self->config->controller."/api/station/".$self->config->macaddress."/partial");
    }
  }
}

with('App::EventStreamr::Roles::Logger');

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

App::EventStreamr::Status - A status object

=head1 VERSION

version 0.5

=head1 SYNOPSIS

This package provides core status notification methods.

=head1 DESCRIPTION

Whilst at it's core EventStreamr Starts/Stops processes, the ability 
to notify when something goes wrong and can't be fixed by itself is
the primary job.

It provides some convenience methods to keep the Run/Stop code nice 
and simple. It also is intended to be passed around as a reference
to ensure state is maintained across the application.

=head1 AUTHOR

Leon Wright < techman@cpan.org >

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2014 by Leon Wright.

This is free software, licensed under:

  The GNU Affero General Public License, Version 3, November 2007

=cut
