package DX::Step::EnterRecheck;

use DX::Step::CompleteRecheck;
use DX::Step::FailRecheck;

use DX::Class;

with 'DX::Role::Step';

has proposition_list => (
  is => 'ro', isa => PropositionList, required => 1
);

has on_completion_step => (is => 'ro', isa => Step, required => 1);

has on_failure_step => (is => 'ro', isa => Maybe[Step], required => 1);

sub apply_to {
  my ($self, $old_ss) = @_;

  my ($prop, @rest) = @{$self->proposition_list};

  trace recheck => [ statement => [
    [ symbol => 'recheck' ],
    @{$prop->for_deparse->[1]},
    [ 'enter_block' ],
  ] ];

  my $old_hyp = $old_ss->current_hypothesis;

  # we should probably be doing something about pruning the scope
  # but that's completely pointless until we have rules (and also,
  # the lock_to_depth arg needs to come from the proposition somehow)

  my $ap = DX::ActionPolicy::LockScope->new(
    lock_to_depth => $old_hyp->scope->depth,
    next_policy => $old_hyp->action_policy,
  );

  my $hyp = ref($old_hyp)->new(
    scope => $old_hyp->scope,
    resolved_propositions => DX::ResolvedPropositionSet->new_empty,
    actions => [],
    action_applications => [],
    action_policy => $ap,
  );

  my $pseq = DX::PropositionSequence->new(
    members => [ $prop ],
    external_names => {},
    internal_names => {},
  );

  my $next_step = (@rest
                    ? $self->but(proposition_list => \@rest)
                    : $self->on_completion_step);

  my $ss = DX::SearchState->new(
    current_hypothesis => $hyp,
    adjustments_made => [],
    propositions => $pseq,
    next_step => DX::Step::ConsiderProposition->new(
                   proposition => $prop,
                 ),
    is_solution_state => 0,
    on_solution_step => DX::Step::CompleteRecheck->new(
      resume_search_state => $old_ss->but(next_step => $next_step),
      was_recheck_for => $prop,
    ),
    on_exhaustion_step => DX::Step::FailRecheck->new(
      resume_search_state => $old_ss->but(next_step => $self->on_failure_step),
    ),
  );

  return $ss;
}

1;
