package DX::ResultStream;

use Moo;

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

has _current_state => (is => 'rw');

has is_exhausted => (is => 'rwp');

has observation_policy => (is => 'ro', default => sub { sub { 0 } });

sub next {
  my ($self) = @_;
  return if $self->is_exhausted;
  my $state = do {
    if (my $cur = $self->_current_state) {
      $cur->push_backtrack;
    } else {
      $self->for_state
    }
  };
  STATE: while ($state = $self->_current_state($state->run)) {
    last if $state->isa('DX::State');
    if ($state->isa('DX::ObservationRequired')) {
      if ($self->observation_policy->($state->observer)) {
        my ($type, $value) = $state->observer->run;
        $state = $state->resume;
        $state->facts->{$type}->set_value($value);
      } else {
        die "Observation refused";
      }
    } else {
      die "WTF: ".$state;
    }
  }
  unless ($state) {
    $self->_set_is_exhausted(1);
    return;
  }
  return +{
    map +($_ => $state->scope_var($_)->bound_value), keys %{$state->scope}
  };
}

sub results {
  my ($self) = @_;
  my @all;
  while (my $next = $self->next) {
    push @all, $next;
  }
  return @all;
}

1;
