#!perl
# deck related tests
use 5.26.0;
use warnings;
use Test2::V0;
use Game::Deckar;

plan(38);

########################################################################
#
# Empty Object

{
    my $deck = Game::Deckar->new;
    like dies { $deck->collect('nope') },  qr/no such deck/;
    like dies { $deck->del_deck('nope') }, qr/no such deck/;
    like dies { $deck->empty('nope') },    qr/no such deck/;
    like dies { $deck->get('deck') },      qr/no such deck/;
    like dies { $deck->get_decks },        qr/no decks/;
    like dies { $deck->shuffle('nope') },  qr/no such deck/;
}

########################################################################
#
# A Reasonable Deck

{
    my $deck = Game::Deckar->new(
        decks   => [qw/deck player1 player2 discard/],
        initial => { deck => [ 'Z', 'A' .. 'F' ], },
    );

    like dies { $deck->add_deck('player1') },    qr/deck already exists/;
    like dies { $deck->collect('deck') },        qr/not enough decks/;
    like dies { $deck->deal( 'nope', 'nope' ) }, qr/no such deck/;
    like dies { $deck->deal( 'player1', 'nope' ) },     qr/no such deck/;
    like dies { $deck->deal( 'player1', 'player2' ) },  qr/too few cards/;
    like dies { $deck->deal( 'deck', 'player1', -1 ) }, qr/out of range/;
    like dies { $deck->deal( 'deck', 'player1', 8 ) },  qr/out of range/;
    like dies { $deck->empty('player1') },              qr/deck is empty/;
    like dies { $deck->shuffle('player1') },            qr/deck is empty/;

    is [ $deck->get_decks ], [qw/deck discard player1 player2/];

    my $unadd = $deck->add_deck('foo');
    is [ $deck->get_decks ], [qw/deck discard foo player1 player2/];
    $unadd->();

    is $deck->get('deck'),    [ 'Z', 'A' .. 'F' ];
    is $deck->get('discard'), [];

    my $unempty = $deck->empty('deck');
    is $deck->get('deck'), [];

    my $undel = $deck->del_deck('deck');
    is [ $deck->get_decks ], [qw/discard player1 player2/];
    $undel->();
    is [ $deck->get_decks ], [qw/deck discard player1 player2/];

    $unempty->();
    is $deck->get('deck'), [ 'Z', 'A' .. 'F' ];

    srand(640);
    my $undo = $deck->shuffle('deck');
    is $deck->get('deck'), [qw(A B Z E F D C)];
    $undo->();
    is $deck->get('deck'), [ 'Z', 'A' .. 'F' ];

    my @log;

    my ( $card, $un ) = $deck->deal( deck => 'player1' );
    is $card, 'Z';
    unshift @log, $un;

    # default destination is to the "top", or index 0
    ( undef, $un ) = $deck->deal( deck => 'player1', 0, 1 );
    unshift @log, $un;
    is $deck->get('player1'), [qw(A Z)];

    # deal to the "bottom" of the target deck, or past the last index
    ( undef, $un ) = $deck->deal( deck => 'player1', 0, 0 );
    unshift @log, $un;
    is $deck->get('player1'), [qw(A Z B)];

    $_->() for @log;
    is $deck->get('deck'),    [ 'Z', 'A' .. 'F' ];
    is $deck->get('player1'), [];

    # "pick" or "take" from a custom index
    ( $card, $un ) = $deck->deal( deck => 'player1', 2 );
    is $card, 'B';
    $un->();
    is $deck->get('deck'), [ 'Z', 'A' .. 'F' ];
}

########################################################################
#
# Deck with ::Card objects and the means to mass set metadata

{
    my $deck = Game::Deckar->new(
        # NOTE "initial" autovivifies decks, for better or worse, so
        # "stack" is also created in decks
        decks         => [qw/p1 p2/],
        initial_cards => { stack   => [ 'A' .. 'C' ] },
        meta          => { visible => 0 },
    );

    my $ref = $deck->get('stack');
    is $ref->[1]->data,            'B';
    is $ref->[1]->meta('visible'), 0;

    $deck->deal( stack => 'p1' );    # 'A'
    $deck->deal( stack => 'p2' );    # 'B', with 'C' still on stack

    # cards are put onto the "top" of the target in the order listed
    my $undo = $deck->collect(qw(stack p1 p2));
    # so this should have B, A, C on stack
    is [ map { $_->data } $deck->get('stack')->@* ], [qw(B A C)];

    $undo->();
    is $deck->get('stack')->[0]->data, 'C';
    is $deck->get('p1')->[0]->data,    'A';
    is $deck->get('p2')->[0]->data,    'B';
}
