package DX::Predicate::MemberAt;

use DX::Utils qw(step INDICES_OF EXISTENCE_OF CONTENTS_OF string);
use DX::ActionBuilder::ProxySetToAdd;
use DX::ActionBuilder::Null;
use DX::Class;

with 'DX::Role::Predicate';

sub _possible_resolution_list {
  my ($self, $coll, $key, $value) = @_;
  die "First argument to member_at must be a structured value"
    unless $coll->does('DX::Role::StructuredValue');
  my $basic_deps = sub {
    (depends_on => [
      [ undef ,=>
        [ EXISTENCE_OF ,=> $coll, ($_[1]||$_[0])->string_value ],
        [ CONTENTS_OF ,=> $_[0] ],
      ],
      [ $value ,=>
        [ CONTENTS_OF ,=> $coll, ($_[1]||$_[0])->string_value ],
        [ CONTENTS_OF ,=> $value ],
      ],
    ])
  };
  if ($value->is_set) {
    # Already set values are only supported for recheck
    trace member_at => "+D +K +V";
    return () unless $key->is_set and my $cur_val = $coll->get_member_at($key);
    return () unless $cur_val->equals($value);
    return step(
      actions => [],
      $basic_deps->($key),
    );
  }
  die "Bizarre: member_at called with non-fresh unset value"
    unless $value->action_builder->isa('DX::ActionBuilder::UnsetValue');
  if ($key->is_set) { 
    trace member_at => "+D +K -V";
    if (my $cur_val = $coll->get_member_at($key)) {
      my $set = $value->action_for_set_value($cur_val);
      return step(
        actions => [ $set ],
        $basic_deps->($key),
      );
    }
    if (my $p = $coll->value_path) {
      my @path = (@$p, $key->string_value);
      my $ab = DX::ActionBuilder::ProxySetToAdd->new(
        target_path => \@path,
        proxy_to => $coll->action_builder,
      );
      my $set = $value->action_for_set_value(
                  $value->but(
                    action_builder => $ab
                  )
                );
      return step(
        actions => [ $set ],
        $basic_deps->($key),
      );
    }
    return ();
  }
  die "Bizarre: member_at called with non-fresh unset key"
    unless $key->action_builder->isa('DX::ActionBuilder::UnsetValue');
  trace member_at => "+D -K -V";
  return map {
           my $set_key = $key->action_for_set_value(my $kstr = string($_));
           my $set_value = $value->action_for_set_value($coll->get_member_at($kstr));
           step(
             actions => [ $set_key, $set_value ],
             $basic_deps->($key, $kstr),
           );
         } $coll->index_list;
}

sub selection_depends_on {
  my ($self, $coll, $key, $value) = @_;
  die "NEEDS REDOING";
  [ [ $coll => ($key->can_set_value ? INDICES_OF : (EXISTENCE_OF ,=> $key)) ],
    $key,
    $value,
  ]
}

1;
