package Net::Async::Redis::Cluster::Multi;

use strict;
use warnings;

our $VERSION = '6.002'; # VERSION

=head1 NAME

Net::Async::Redis::Multi - represents multiple operations in a single Redis transaction

=head1 DESCRIPTION

Instances are generated by L<Net::Async::Redis/multi>.

=cut

use Syntax::Keyword::Try;
use Syntax::Keyword::Dynamically;
use Future::AsyncAwait;
use Scalar::Util qw(weaken blessed);
use Sub::Util qw(set_subname);

use Log::Any qw($log);

sub new {
    my ($class, %args) = @_;
    $args{queued_requests} //= [];
    weaken($args{redis} // die 'Must be provided a Net::Async::Redis instance');
    bless \%args, $class;
}

async sub exec {
    my ($self, $code) = @_;

    try {
        my $f = $self->$code;
        $f->retain if blessed($f) and $f->isa('Future');
        return 0;
    } catch {
        my $err = $@;
        $log->errorf('Failed to complete multi - %s', $err);
        die $@;
    }
}

=head2 redis

Accessor for the L<Net::Async::Redis> instance.

=cut

sub redis { shift->{redis} }

sub AUTOLOAD {
    my ($method) = our $AUTOLOAD =~ m{::([^:]+)$};

    # We only need to check this once
    die "Unknown method $method" unless Net::Async::Redis::Commands->can($method);

    my $code = async sub {
        my ($self, @args) = @_;
        my $f = $self->redis->future->set_label($method);
        push @{$self->{queued_requests}}, $f;
        my $node = await $self->redis->find_node($method => @args);
        my $multi = $self->{multi}{$node->id} or die 'node not found - ' . $node;
        return await $multi->$method(@args);
    };
    set_subname $method => $code;
    { no strict 'refs'; *$method = sub { $code->(@_)->retain } }
    $code->(@_)->retain;
}

sub DESTROY {
    my ($self) = @_;
    return if ${^GLOBAL_PHASE} eq 'DESTRUCT' or not $self->{queued_requests};

    for my $queued (splice @{$self->{queued_requests}}) {
        try {
            $queued->cancel;
        } catch {
            $log->warnf("Failure during cleanup: %s", $@);
        }
    }
}

1;

__END__

=head1 AUTHOR

Tom Molesworth C<< <TEAM@cpan.org> >> plus contributors as mentioned in
L<Net::Async::Redis/CONTRIBUTORS>.

=head1 LICENSE

Copyright Tom Molesworth 2015-2024. Licensed under the same terms as Perl itself.

