package App::EventStreamr::Roles::ConfigAPI;

use v5.010;
use strict;
use warnings;
use Config::JSON;
use JSON;
use Method::Signatures 20140224; # libmethod-signatures-perl
use HTTP::Tiny '0.053'; # libhttp-tiny-perl
use Proc::ProcessTable; # libproc-processtable-perl

use Moo::Role; # libmoo-perl

# ABSTRACT: A config api

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


requires 'write_config','localconfig','config_path','macaddress','devices';

has 'controller_config' => ( is => 'ro', lazy => 1, builder => 1 );
has 'controller'        => ( is => 'rw', lazy => 1, builder => 1 );
has 'remote_config'     => ( is => 'rw', lazy => 1, builder => 1 );
has 'http'              => ( is => 'rw', lazy => 1, builder => 1, handles => [ qw( post get ) ] );
has 'api_url'           => ( is => 'ro', default => sub { "http://127.0.0.1:3000/internal/settings" } );


method _build_http() {
  return HTTP::Tiny->new(timeout => 15);
}

method _build_controller_config() {
  return $self->config_path."/controller.json";
}

method _build_controller() {
  if ( -e $self->controller_config ) {
    return Config::JSON->new($self->controller_config)->config->{controller};
  } else {
    return 0;
  }
}

method _build_remote_config() {
  # We're designed to operate without a controller.
  return 0 if (! $self->controller);
  
  $self->info("Registering with controller ".$self->controller."/api/station/".$self->macaddress);
  my $response = $self->http->post($self->controller."/api/station/".$self->macaddress);

  # Controller responds with created 201, post our config.
  # This occurs when our identifier isn't registered in the
  # Frontend.
  if ($response->{status} == 201) {
    # Status Post Data
    my $json = to_json($self->_post_data());
    $self->debug($json);
     
    my %post_data = (
          content => $json,
          headers => {
            'station-mgr' => 1,
            'Content-Type' => 'application/json',
          } 
    );
  
    $response = $self->http->post($self->controller."/api/station", \%post_data);
  }

  # We get a 200 if exist and are already registered. Previous 
  # if block takes care of requesting config after registering.
  if ($response->{status} == 200 ) {
    $self->debug({filter => \&Data::Dumper::Dumper,
                    value  => $response}) if ($self->is_debug());

    if (defined $response->{content} && $response->{content} ne 'true') {
      my $content = from_json($response->{content});
      return $content->{settings};
    }
    return 0;
  } else {
    return 0;
  }
}

# Although this works, it's rather horrible. We really should
# use the accessors properly and we wouldn't have to ignore
# them and do this (I'll however settle for working first up).
after '_load_config' => sub {
  my $self = shift;
  
  if ( $self->remote_config ) {
    # Eww code duplication of _load_config. Same applies.
    foreach my $key (keys %{$self->{remote_config}}) {
      $self->{$key} = $self->{remote_config}{$key};
    }
    $self->write_config();
  } else {
    $self->post_config();
  }
};

after 'write_config' => sub {
  my $self = shift;
  $self->post_config();
};

method post_config() {
  $self->update_devices();

  # Post config to manager api
  my $json = to_json($self->_post_data());
  my %post_data = (
    content => $json,
    'content-type' => 'application/json',
    'content-length' => length($json),
  );
  my $post = $self->http->post(
    $self->api_url,
    \%post_data,
  );
  
  if ( $self->remote_config ) {
    # Post devices to controller.
    $self->info("posting devices to controller");
    my $data;
    $data->{key} = "devices";
    @{$data->{value}} = @{$self->{available_devices}{array}};

    # I don't think this is needed!
    #$json = to_json($data);
    ## FROM ORIGINAL CODE:
    ## some bug and it's late this could cause hideous issues if 
    ## a device id has a / in it, but this should be unlikely
    #$json =~ s{/|\.}{}g;
  
    %post_data = (
      content => to_json($data),
      headers => {
        'station-mgr' => 1,
        'Content-Type' => 'application/json',
      }
    );

    $post = $self->http->post(
      $self->controller."/api/station/".$self->macaddress."/partial", 
      \%post_data,
    );
  
    $self->debug({filter => \&Data::Dumper::Dumper,
                    value  => $post}) if ($self->is_debug());
  }
}

method get_config() {
  $self->info("Retrieving config from manager API");
  my $get = $self->http->get($self->api_url);
  my $content = from_json($get->{content});
  
  $self->debug({filter => \&Data::Dumper::Dumper,
                  value  => $get}) if ($self->is_debug());


  # Eww code duplication of _load_config. Same appliest.
  foreach my $key (keys %{$content->{config}}) {
    $self->{$key} = $content->{config}{$key};
  }
  $self->write_config();
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

App::EventStreamr::Roles::ConfigAPI - A config api

=head1 VERSION

version 0.5

=head1 SYNOPSIS

This is a role wraps around the 'run_stop' of a process.

=head1 DESCRIPTION

This is a Role that can be consumed to post config to the internal
and controller APIs.

It requires a methods from the config package, so really should only 
be consumed by L<App::EventStreamr::Config>.

=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
