package Tak::ObjectClient;

use Tak::ObjectProxy;
use Moo;

with 'Tak::Role::ObjectMangling';

has world => (is => 'ro', required => 1);

has remote => (is => 'lazy');

sub _build_remote {
  my ($self) = @_;
  my $world = $self->world;
  $world->remote_for('meta')->blocking_request(
    register => object_service => 'Tak::ObjectService'
  );
  $world->remote_for('object_service')
}

sub proxy_method_call {
  my ($self, @call) = @_;
  my $ready = $self->encode_objects(\@call);
  my $context = wantarray;
  my @res = $self->remote->blocking_request(call_method => $context => $ready);
  if ($res[0] eq 'RESULT') {
    my $unpacked = $self->decode_objects($res[1]);
    if ($context) {
      return @$unpacked;
    } elsif (defined $context) {
      return $unpacked->[0];
    } else {
      return;
    }
  } else {
    die $res[1];
  }
}

sub proxy_death {
  my ($self, $proxy) = @_;
  $self->remote->blocking_request(remove_object => $proxy->{tag});
}

sub inflate {
  my ($self, $tag) = @_;
  bless({ client => $self, tag => $tag }, 'Tak::ObjectProxy');
}

sub deflate {
  my ($self, $obj) = @_;
  unless (ref($obj) eq 'Tak::ObjectProxy') {
    die "Can't deflate non-proxied object ${obj}";
  }
  return +{ __proxied_object__ => $obj->{tag} };
}

sub new_object {
  my ($self, $class, @args) = @_;
  $self->proxy_method_call($class, 'new', @args);
}

1;
