#!perl
use warnings; use strict;
use Test::More tests => 30;
use Test::Exception;
use Test::Builder;

use lib '.';
use t::Elive;

use Carp;
use version;

use Elive;
use Elive::Entity::Meeting;
use Elive::Entity::ParticipantList;

our $t = Test::Builder->new;
our $class = 'Elive::Entity::Meeting' ;

our $connection;

SKIP: {

    my %result = t::Elive->test_connection( only => 'real');
    my $auth = $result{auth};

    skip ($result{reason} || 'skipping live tests', 30)
	unless $auth;

    my $connection_class = $result{class};
    my $connection = $connection_class->connect(@$auth);
    Elive->connection($connection);

    #
    # ELM 3.3.4 / 10.0.2 includea significant bug fixes
    our $elm_3_3_4_or_better =  (version->declare( $connection->server_details->version )->numify
				 > version->declare( '10.0.1' )->numify);

    my $meeting_start = time();
    my $meeting_end = $meeting_start + 900;

    $meeting_start .= '000';
    $meeting_end .= '000';

    my %meeting_data = (
	name => 'test meeting, generated by t/31-soap-participants.t',
	facilitatorId => Elive->login->userId,
	password => 'test', # what else?
	start =>  $meeting_start,
	end => $meeting_end,
	privateMeeting => 1,
    );

    my ($meeting) = $class->insert(\%meeting_data);

    isa_ok($meeting, $class, 'meeting');

    my $participants_deep_ref = [{user => Elive->login->userId,
				  role => 2}];
    #
    # NB. not neccessary to insert prior to update, but since we allow it
    lives_ok(
	sub {my $_p = Elive::Entity::ParticipantList->insert(
		 {meetingId => $meeting->meetingId,
		  participants => $participants_deep_ref});
	     diag ("participants=".$_p->participants->stringify);
	},
	'insert of participant deep list - lives');

    my $participant_list = Elive::Entity::ParticipantList->retrieve([$meeting->meetingId]);

    isa_ok($participant_list, 'Elive::Entity::ParticipantList', 'server_params');
    is($participant_list->participants->stringify, Elive->login->userId.'=2',
       'participant deep list - set correctly');

    $participant_list->participants([Elive->login->userId.'=1']);
    is($participant_list->participants->stringify, Elive->login->userId.'=1',
       'participant shallow list - set correctly');

    lives_ok(sub {$participant_list->update()}, 'participant list update - lives');
    is($participant_list->participants->stringify, Elive->login->userId.'=2',
       'participant list update - has reset moderator privileges');

    $participant_list->update({participants => Elive->login->userId.'=2'});

    diag ("participants=".$participant_list->participants->stringify);

    is($participant_list->participants->stringify, Elive->login->userId.'=2',
       'participant string list - set correctly');

    #
    # lets grab some volunteers from the audience!
    #
    my ($participant1, $participant2, @participants);

    lives_ok( sub {
	#
	# for datasets with 1000s of entries
	($participant1,$participant2, @participants) = grep {$_->userId ne $meeting->facilitatorId} @{ Elive::Entity::User->list(filter => 'lastName = Sm*') };
	#
	# for modest test datasets
	($participant1,$participant2, @participants) = grep {$_->userId ne $meeting->facilitatorId} @{ Elive::Entity::User->list() }
	    unless @participants;
	      },
	      'get_users - lives');

    #
    # only want a handful
    #
    @participants = @participants[0 .. 9]
	if (@participants > 10);

    if ($participant2) {

	$participant_list->participants->add($participant1->userId.'=3');

	lives_ok(sub {$participant_list->update}, 'setting of participant - lives');
	if ($elm_3_3_4_or_better) {
	    ok($meeting->is_participant( $participant1), 'is_participant($participant1)');
	}
	else {
	    $t->skip('is_participant() - broken prior to ELM 3.3.4 / 10.0.2');
	}

	ok(!$meeting->is_moderator( $participant1), '!is_moderator($participant1)');

	ok((grep {$_->user->userId eq $participant1->userId} @{ $participant_list->participants }), 'participant 1 found in participant list');
	ok((grep {$_->user->userId eq $participant1->userId && $_->role->roleId == 3} @{ $participant_list->participants }), 'participant 1 is not a moderator');

	$participant_list->participants->add($participant2->userId.'=3');
	$participant_list->update();

	if ($elm_3_3_4_or_better) {
	    ok($meeting->is_participant( $participant2), 'is_participant($participant2)');
	}   
        else {  
            $t->skip('is_participant() - broken prior to ELM 3.3.4 / 10.0.2');
        }

 	ok(!$meeting->is_moderator( $participant2), '!is_moderator($participant2)');

	ok((grep {$_->user->userId eq $participant2->userId} @{ $participant_list->participants }), 'participant 2 found in participant list');
	ok((grep {$_->user->userId eq $participant2->userId && $_->role->roleId == 3} @{ $participant_list->participants }), 'participant 2 is not a moderator');

    }
    else {
	$t->skip('unable to find any other users to act as participants(?)',)
	    for (1..7);
    }

    $participant_list->reset();

    if (@participants) {
# see todo list in Elive::Entity::ParticipantList
	my @missing;
	my @to_add = ($participant1, $participant2, @participants);
	my @rejected;
	lives_ok( sub {$participant_list->update({participants => \@participants}),
		  }, 'setting up a larger meeting - lives');
    }
    else {
	$t->skip('insufficent users to run large meeting tests', 10);
    }

    ok($meeting->is_participant( Elive->login), 'is_participant($moderator)');
    ok($meeting->is_moderator( Elive->login), 'is_moderator($moderator)');

    my $gate_crasher = 'gate_crasher_'.t::Elive::generate_id();

    ok(!$meeting->is_participant( $gate_crasher ), '!is_participant($gate_crasher)');
    ok(!$meeting->is_moderator( $gate_crasher ), '!is_moderator($gate_crasher)');

    dies_ok(sub {
	$participant_list->participants->add($gate_crasher.'=3');
	$participant_list->update($gate_crasher.'=3');
	    },
	    'add of unknown participant - dies');

    lives_ok(sub {$participant_list->update({participants => []})},
	     'clearing participants - lives');

    my $p = $participant_list->participants;

    #
    # check our reset policy. Updating/creating an empty participant
    # list is effectively the same as a reset. Ie, we end up with
    # the facilitator as the sole participant, with a role of moderator (2).
    #

    is(@$p, 1, 'participant_list reset - single participant');

    is($p->[0]->user && $p->[0]->user->userId, $meeting->facilitatorId,
       'participant_list reset - single participant is the facilitator');

    is($p->[0]->role && $p->[0]->role->roleId, 2,
       'participant_list reset - single participant has moderator role');

    if (! $elm_3_3_4_or_better ) {
	#
	# The next test verifies bug fixes under ELM 3.3.4/10.0.2. It probably wont
	# work with 10.0.1 or earlier.
	#
	$t->skip('skipping participant long-list test for Elluminate < v10.0.2');
    }
    elsif ($participant2) { 
	#
	# stress test underlying setParticipantList command we need to do a direct SOAP
	# call to bypass overly helpful readback checsk and removal of duiplicates.
	#
	my @big_user_list;

      MAKE_BIG_LIST:
	while (1) {
	    foreach ($participant1, $participant2, @participants) {
		#
		# include a smattering of unknown users
		#
		my $user = rand() < .1 ? t::Elive::generate_id(): $_->userId;
		push (@big_user_list, $user);
		last MAKE_BIG_LIST
		    if @big_user_list > 2500;
	    }
	}

	my $participants_str = Elive->login->userId.'=2;'.join(';', map {$_.'=3'} @big_user_list);
	lives_ok(sub{$participant_list->_set_participant_list($participants_str)},
		  'participants long-list test - lives'
	    );
    }
    else {
	$t->skip('not enough participants to run long-list test');
    }

    #
    # tidy up
    #

    lives_ok(sub {$meeting->delete},'meeting deletion');
}

Elive->disconnect;

