<?php

namespace Tests\Browser;

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\WithFaker;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
use Illuminate\Support\Arr;
use Facebook\WebDriver\WebDriverBy;

use Carbon\Carbon;

use Tests\Browser\Pages\Login;
use Tests\Browser\Components\Feedback;
use Tests\Browser\Components\DateTimePicker;
use Tests\Browser\Components\Autocomplete;
use Tests\Browser\Components\SelectButtons;
use Tests\Browser\Components\Editor;

use App\Models\User;
use App\Models\Livestream;
use App\Models\Tag;
use App\Models\Role;
use App\Models\LivestreamRegistration;
use App\Models\Chat;
use App\Models\Inquiry;

class LivestreamTest extends DuskTestCase
{
    use WithFaker;

    public function test_a_livestream_can_be_created()
    {
        $this->browse(function ($browser) {
            $user = User::factory()->create();

            $browser->visit(new Login())
                ->loginUser($user)
                ->visit(route('livestreams.index'))
                ->pause(1000)
                ->assertMissing('@livestreams-index');
            /*
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('You do not have access to view Livestreams');
                });
             */

            $user->addRole('livestreams-manager');
            $user->refresh();

            $browser->visit(new Login())
                ->loginUser($user)
                ->visit(route('livestreams.index'))
                ->waitForRoute('livestreams.index')
                ->waitFor('@livestreams-index')
                ->waitFor('@livestreams-paginator')
                ->waitFor('@create-livestream')
                ->click('@create-livestream');

            $input = Livestream::factory()->raw();

            $browser->with('@modal', function ($browser) {
                $browser->with('@livestream-form', function ($browser) {
                    $browser->waitFor('@save-livestream')
                        ->click('@save-livestream');
                });
            });

            $browser->within(new Feedback(), function ($browser) {
                $browser->assertFeedbackContains('The name field is required')
                    //->assertFeedbackContains('The video id field is required')
                    ->assertFeedbackContains('The start date field is required');
            });

            $moderator = User::factory()->create();
            $moderator->addRole('livestreams-manager');
            $tag = Tag::factory()->create();
            $role = Role::factory()->create();

            $browser->with('@modal', function ($browser) use ($input, $moderator, $tag, $role) {
                $browser->with('@livestream-form', function ($browser) use ($input, $moderator, $tag, $role) {
                    $browser->type('@name', Arr::get($input, 'name'))

                        ->within(new Editor('description', '0.1'), function ($browser) use ($input) {
                            $browser->typeInEditor(Arr::get($input, 'description'));
                        })

                        ->type('@video_id', Arr::get($input, 'video_id'))
                        ->pause(2500)
                        ->with(new DateTimePicker('start_date'), function ($browser) use ($input) {
                            $browser->selectDateTime(Arr::get($input, 'start_date'));
                        })
                        ->with(new Autocomplete('moderator'), function ($browser) use ($moderator) {
                            $browser->searchAndSelectMultiple($moderator);
                        })
                        ->with(new Autocomplete('role'), function ($browser) use ($role) {
                            $browser->searchAndSelectMultiple($role);
                        })
                        ->type('@length', Arr::get($input, 'length'));

                    $end_string = Carbon::parse(Arr::get($input, 'start_date'))
                        ->setTimezone('America/Vancouver')
                        ->addMinutes(Arr::get($input, 'length'))
                        ->format('Y-m-d G:i');

                    //dump(Arr::get($input, 'start_date'));

                    $browser->waitFor('@end-date')
                        ->pause(250)
                        ->assertSeeIn('@end-date', $end_string)

                        ->with(new Autocomplete('tags'), function ($browser) use ($tag) {
                            $browser->searchAndSelectMultiple($tag);
                        })
                        ->with(new SelectButtons('chat_mode'), function ($browser) use ($input) {
                            $browser->selectButtons(Arr::get($input, 'chat_mode'));
                        })
                        ->click('@checkbox-unlisted')
                        //->pause(250)
                        //->assertMissing('@autocomplete-role')
                        ->click('@checkbox-unlisted')
                        //->pause(250)
                        //->assertVisible('@autocomplete-role')
                        ->click('@checkbox-can_register')
                        ->click('@save-livestream');
                });
            });

            $browser->within(new Feedback(), function ($browser) use ($input) {
                $browser->assertFeedbackContains(Arr::get($input, 'name').' Saved');
            });

            $livestream = Livestream::all()->last();

            $browser->with('@livestreams-paginator', function ($browser) use ($livestream) {
                $browser->type('@paginator-search', $livestream->name);
            })
                ->waitFor('@edit-livestream-'.$livestream->id)
                ->click('@edit-livestream-'.$livestream->id)

                ->with('@modal', function ($browser) use ($input, $moderator, $tag, $role, $livestream) {
                    $browser->with('@livestream-form', function ($browser) use ($input, $moderator, $tag, $role, $livestream) {
                        $browser->assertVue('livestream.name', Arr::get($input, 'name'))
                            ->assertVue('livestream.description', '<p>'.Arr::get($input, 'description').'</p>')
                            ->assertVue('livestream.video_id', Arr::get($input, 'video_id'))
                            ->assertVue('livestream.start_date', Arr::get($input, 'start_date')->toJson())
                            ->assertVue('livestream.length', Arr::get($input, 'length'))
                            ->assertVue('livestream.chat_mode', Arr::get($input, 'chat_mode'))
                            ->assertVue('livestream.unlisted', true)
                            ->assertVue('livestream.can_register', true)

                            ->assertValue('@name', $livestream->name)
                            ->with('@description-editor-'.$livestream->id, function ($browser) use ($livestream) {
                                $browser->assertSourceHas($livestream->description);
                            })
                            ->assertValue('@video_id', $livestream->video_id)
                            ->assertValue('@length', $livestream->length);
                    });
                });
        });
    }

    public function test_users_can_register_and_join_a_livestream_with_chat()
    {
        $this->browse(function ($browser, $guest, $third) {
            $manager = User::factory()->create();
            $manager->addRole('livestreams-manager');
            $mod = User::factory()->create();
            $input = collect(User::factory()->raw())->only('name', 'email')->toArray();
            $tag = Tag::where('name', 'like', '%open house%')->first();
            $this->assertInstanceOf(Tag::class, $tag);

            $browser->visit(new Login())
                ->loginUser($manager)
                ->visit(route('livestreams.index'))
                ->waitForRoute('livestreams.index')
                ->waitFor('@livestreams-index')
                ->waitFor('@livestreams-paginator')
                ->waitFor('@create-livestream')
                ->click('@create-livestream');

            $input = Livestream::factory()->raw([
                //'start_date' => now()->setTimezone('America/Vancouver'),,
                'length' => 600,
                'chat_mode' => 'private',
                'can_register' => true,
            ]);

            $browser->with('@modal', function ($browser) use ($input, $mod, $tag) {
                $browser->with('@livestream-form', function ($browser) use ($input, $mod, $tag) {
                    $browser->waitFor('@name')
                        ->type('@name', Arr::get($input, 'name'))

                        ->waitFor('@description-editor-0.1')
                        ->within(new Editor('description', '0.1'), function ($browser) use ($input) {
                            $browser->typeInEditor(Arr::get($input, 'description'));
                        })

                        ->type('@video_id', Arr::get($input, 'video_id'))
                        ->with(new DateTimePicker('start_date'), function ($browser) use ($input) {
                            $browser->selectDateTime(Arr::get($input, 'start_date'));
                        })
                        ->with(new Autocomplete('moderator'), function ($browser) use ($mod) {
                            $browser->searchAndSelectMultiple($mod);
                        })
                        ->type('@length', Arr::get($input, 'length'))

                        ->with(new Autocomplete('tags'), function ($browser) use ($tag) {
                            $browser->searchAndSelectMultiple($tag, 25);
                        })
                        ->with(new SelectButtons('chat_mode'), function ($browser) use ($input) {
                            $browser->selectButtons(Arr::get($input, 'chat_mode'));
                        })
                        ->click('@checkbox-unlisted')
                        ->click('@checkbox-can_register')
                        ->click('@save-livestream');
                });
            });

            $browser->within(new Feedback(), function ($browser) use ($input) {
                $browser->assertFeedbackContains(Arr::get($input, 'name').' Saved');
            });

            $livestream = Livestream::all()->last();
            $this->assertFalse($livestream->unlisted);

            $guest->visit('/live')
                   ->waitFor('@paginator-upcoming-events', 20)
                    ->with('@paginator-upcoming-events', function ($guest) use ($livestream) {
                        $guest->type('@paginator-search', $livestream->name);
                    })
                   ->waitFor('@livestream-'.$livestream->id)
                   ->with('@livestream-'.$livestream->id, function ($guest) use ($livestream) {
                       $guest->waitFor('@register-now-'.$livestream->id)
                           ->pause(500)
                           ->click('@register-now-'.$livestream->id);
                   })->pause(2000);

            $user_input = User::factory()->raw();

            $guest->with('@modal', function ($guest) use ($user_input) {
                $guest->with('@livestream-registration-form', function ($guest) use ($user_input) {
                    $guest->waitFor('@name')
                        ->type('@name', Arr::get($user_input, 'name'))
                        ->type('@email', Arr::get($user_input, 'email'))
                        ->click('@next')
                        ->waitFor('@start-year-'.now()->addYears(1)->format('Y'))
                        ->pause(250)
                        ->click('@start-year-'.now()->addYears(1)->format('Y'))
                        ->click('@grade-10')
                        ->click('@next');

                    if (Inquiry::getTags()->count()) {
                        $guest->pause(250)
                            ->waitFor('@next')
                            ->click('@next');
                    }

                    $guest->waitFor('@finish')
                        ->click('@finish');
                });
            });

            $guest->within(new Feedback(), function ($guest) {
                $guest->assertFeedbackContains('Registration Complete');
            });

            $guest->with('@modal', function ($guest) use ($livestream) {
                $guest->waitFor('@livestream-registration-complete')
                    ->with('@livestream-registration-complete', function ($guest) use ($livestream) {
                        $guest->assertSee($livestream->name.' Registration Complete')
                            ->click('@close');
                    });
            });

            $livestream_registration = LivestreamRegistration::all()->last();
            $attendee = $livestream_registration->user;
            $this->assertEquals(Arr::get($user_input, 'email'), $attendee->email);
            $this->assertEquals($livestream_registration->user->email, $attendee->email);

            $message = Arr::get(Chat::factory()->raw(), 'message');
            $this->assertNotNull($message);

            $guest->pause(1000)
                    ->visit($livestream_registration->url)
                    ->pause(1000)
                    ->assertAuthenticatedAs($attendee)
                    //->visit($livestream_registration->url)
                    ->pause(1000)
                    ->assertPathIs('/livestreams/'.$livestream->id)
                    ->waitFor('@player-livestream-'.$livestream->id)
                    ->waitFor('@chat-room-'.$livestream->chat_room)
                    ->with('@chat-room-'.$livestream->chat_room, function ($guest) use ($message) {
                        $guest->type('@message', $message)
                              ->keys('@message', ['{enter}'])
                              ->pause(500);
                    });

            $chat_message = Chat::all()->last();

            $guest->with('@chat-room-'.$livestream->chat_room, function ($guest) use ($chat_message) {
                $guest->waitFor('@chat-message-'.$chat_message->id)
                    ->assertSeeIn('@chat', $chat_message->message);
            });

            $browser->visitRoute('livestreams.index')
                ->with('@livestreams-paginator', function ($browser) use ($livestream) {
                    $browser->waitFor('@paginator-search')
                        ->type('@paginator-search', $livestream->name);
                })
                ->waitFor('@livestream-'.$livestream->id)
                ->pause(500)
                ->with('@livestream-'.$livestream->id, function ($browser) use ($livestream_registration, $attendee) {
                    $browser->assertSee('1 Registered')
                        ->click('@toggle-registered')
                        ->pause(250)
                        ->waitFor('@livestream-registration-'.$livestream_registration->id)
                        ->with('@livestream-registration-'.$livestream_registration->id, function ($browser) use ($attendee, $livestream_registration) {
                            $browser->assertSee($attendee->name)
                                    ->assertSee($attendee->email)
                                ->click('@checkbox-select-registration-'.$livestream_registration->id);
                        })
                        ->waitFor('@send-reminder-emails')
                        ->click('@send-reminder-emails');
                })
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('1 Reminder Emails Queued To Send');
                })
                ->with('@livestream-'.$livestream->id, function ($browser) use ($livestream) {
                    $browser->click('@copy-invite-link');
                })
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Copied to clipboard');
                })
                ->with('@livestream-'.$livestream->id, function ($browser) use ($livestream) {
                    $browser->click('@event-page');
                })
                ->waitForRoute('livestreams.view', ['id' => $livestream->id])
                ->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($chat_message) {
                    $browser->waitFor('@chat-message-'.$chat_message->id)
                        ->assertSeeIn('@chat', $chat_message->message);
                });

            $attendee2 = User::factory()->create();
            $livestream->registerUser($attendee2);
            $livestream_registration2 = LivestreamRegistration::all()->last();

            $message2 = Arr::get(Chat::factory()->raw(), 'message');

            $third->visit($livestream_registration2->url)
                ->pause(1000)
                ->assertAuthenticatedAs($attendee2)
                //->visit($livestream_registration2->url)
                ->waitFor('@chat-room-'.$livestream->chat_room)
                ->with('@chat-room-'.$livestream->chat_room, function ($third) use ($chat_message, $message2) {
                    $third->pause(1000)
                        ->assertDontSeeIn('@chat', $chat_message->message)
                        ->type('@message', $message2)
                        ->keys('@message', ['{enter}'])
                        ->pause(500);
                });

            $chat_message2 = Chat::all()->last();

            $browser->waitFor('@chat-message-'.$chat_message2->id)
                ->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($chat_message2) {
                    $browser->assertSeeIn('@chat', $chat_message2->message);
                });

            $guest->with('@chat-room-'.$livestream->chat_room, function ($guest) use ($chat_message2) {
                $guest->assertDontSeeIn('@chat', $chat_message2->message);
            });

            $browser->click('@select-chat-'.$chat_message2->id)
                    ->waitFor('@selected-chats')
                    ->with('@selected-chats', function ($browser) use ($chat_message2) {
                        $browser->waitFor('@selected-chat-message-'.$chat_message2->id)
                                ->assertSee($chat_message2->message)
                                ->click('@clear-selected-chat-'.$chat_message2->id)
                                ->pause(500);
                    })
                    ->assertMissing('@selected-chats')
                    ->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($chat_message2) {
                        $browser->click('@whisper-user-'.$chat_message2->user->id);
                    })
                    ->waitFor('@whisper-user')
                    ->assertSeeIn('@whisper-user', $chat_message2->user->name);

            $whisper_message = Arr::get(Chat::factory()->raw(), 'message');

            $browser->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($whisper_message) {
                $browser->type('@message', $whisper_message)
                        ->keys('@message', ['{enter}'])
                        ->pause(500);
            });

            $whisper = Chat::all()->last();

            $third->with('@chat-room-'.$livestream->chat_room, function ($third) use ($whisper, $manager) {
                $third->waitFor('@chat-message-'.$whisper->id)
                      ->assertSee($whisper->message)
                      ->with('@chat-message-'.$whisper->id, function ($third) use ($manager) {
                          $third->assertSee($manager->name);
                      });
            });

            $browser->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($whisper_message) {
                $browser->click('@clear-whisper')
                        ->pause(500)
                        ->assertMissing('@whisper-user');
            });

            $delete_message = Arr::get(Chat::factory()->raw(), 'message');

            $guest->with('@chat-room-'.$livestream->chat_room, function ($guest) use ($delete_message) {
                $guest->type('@message', $delete_message)
                      ->keys('@message', ['{enter}'])
                      ->pause(500);
            });

            $delete = Chat::all()->last();

            $browser->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($delete) {
                $browser->waitFor('@chat-message-'.$delete->id)
                        ->assertVisible('@toggle-user-info-'.$delete->id)
                        ->click('@toggle-user-info-'.$delete->id)
                        ->with('@user-info-'.$delete->id, function ($browser) use ($delete) {
                            $browser->click('@delete-'.$delete->id);
                        })
                        ->pause(500)
                        ->assertDontSee('@user-info-'.$delete->id);
            })
            ->within(new Feedback(), function ($browser) use ($input) {
                $browser->assertFeedbackContains('Message Deleted');
            });

            $guest->with('@chat-room-'.$livestream->chat_room, function ($guest) use ($delete) {
                $guest->with('@chat-message-'.$delete->id, function ($guest) use ($delete) {
                    $guest->pause(500)
                        ->assertDontSee($delete->message)
                        ->assertSee('Message Deleted');
                });
            });

            $browser->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($delete) {
                $browser->pause(500)
                        ->click('@toggle-user-info-'.$delete->id)
                        ->with('@user-info-'.$delete->id, function ($browser) use ($delete) {
                            $browser->click('@ban-'.$delete->user_id)
                                ->acceptDialog();
                        })
                        ->pause(500)
                        ->assertDontSee('@user-info-'.$delete->id);
            })
            ->within(new Feedback(), function ($browser) use ($delete) {
                $browser->assertFeedbackContains($delete->user->name.' Banned');
            });

            $guest->with('@chat-room-'.$livestream->chat_room, function ($guest) {
                $guest->assertSee('You have been banned from the Question & Answer');
            });
        }); // end of test
    }

    public function test_mods_only_display_whispers_for_the_channel_that_they_are_in()
    {
        $this->browse(function ($browser, $browser2, $browser3, $admin) {
            $livestream = Livestream::factory()->privateChat()->create();
            $livestream2 = Livestream::factory()->privateChat()->create();

            $mod = User::factory()->create();
            $mod->createPermission('moderate', $livestream);

            $manager = User::factory()->create();
            $manager->addRole('livestreams-manager');

            $attendee = User::factory()->create();
            $livestream2->registerUser($attendee);
            $livestream_registration = LivestreamRegistration::all()->last();

            $message1 = Arr::get(Chat::factory()->raw(), 'message');
            $message2 = Arr::get(Chat::factory()->raw(), 'message');
            $message3 = Arr::get(Chat::factory()->raw(), 'message');

            $super_user = User::factory()->create();
            $super_user->addRole('admin');

            $admin->visit(new Login())
                ->loginUser($super_user)
                ->visitRoute('livestreams.view', ['id' => $livestream->id])
                ->waitForRoute('livestreams.view', ['id' => $livestream->id]);

            $browser3->visit(new Login())
                ->loginUser($manager)
                ->visitRoute('livestreams.view', ['id' => $livestream->id])
                ->waitForRoute('livestreams.view', ['id' => $livestream->id]);

            $browser->visit(new Login())
                ->loginUser($mod)
                ->visitRoute('livestreams.view', ['id' => $livestream->id])
                ->waitForRoute('livestreams.view', ['id' => $livestream->id])
                ->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($message1) {
                    $browser->type('@message', $message1)
                        ->keys('@message', ['{enter}'])
                        ->pause(500);
                });

            $chat1 = Chat::all()->last();

            $browser2->visit($livestream_registration->url)
                ->waitForRoute('livestreams.view', ['id' => $livestream2->id])
                ->assertPathIs('/livestreams/'.$livestream2->id)
                ->with('@chat-room-'.$livestream2->chat_room, function ($browser2) use ($message1, $message2) {
                    $browser2->assertDontSee($message1)
                        ->type('@message', $message2)
                        ->keys('@message', ['{enter}'])
                        ->pause(500);
                });

            $chat2 = Chat::all()->last();

            $browser->pause(500)
                ->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($message2) {
                    $browser->assertDontSee($message2);
                });

            $browser3->pause(500)
                ->with('@chat-room-'.$livestream->chat_room, function ($browser3) use ($message2) {
                    $browser3->assertDontSee($message2);
                });

            $admin->pause(500)
                ->with('@chat-room-'.$livestream->chat_room, function ($admin) use ($message2) {
                    $admin->assertDontSee($message2);
                });

            $admin->visitRoute('livestreams.view', ['id' => $livestream2->id])
                ->waitForRoute('livestreams.view', ['id' => $livestream2->id]);

            $browser2->with('@chat-room-'.$livestream2->chat_room, function ($browser2) use ($message3) {
                $browser2->type('@message', $message3)
                    ->keys('@message', ['{enter}'])
                    ->pause(500);
            });

            $admin->pause(500)
                ->with('@chat-room-'.$livestream2->chat_room, function ($admin) use ($message3) {
                    $admin->assertSee($message3);
                });
        });
    }

    public function test_a_user_has_to_login_to_chat()
    {
        $this->browse(function ($browser) {
            $livestream = Livestream::factory()->privateChat()->create();

            $logged_in = count($browser->driver->findElements(WebDriverBy::id('user-menu')));

            if ($logged_in) {
                $browser->click('@user-menu')
                        ->pause(250)
                        ->clickAndWaitForReload('@logout-button');
            }

            $browser->visit('/live')
                   ->waitFor('@paginator-upcoming-events', 20)
                    ->with('@paginator-upcoming-events', function ($browser) use ($livestream) {
                        $browser->type('@paginator-search', $livestream->name);
                    })
                   ->waitFor('@livestream-'.$livestream->id)
                   ->with('@livestream-'.$livestream->id, function ($browser) use ($livestream) {
                       $browser->waitFor('@register-now-'.$livestream->id)
                           ->pause(500)
                           ->click('@register-now-'.$livestream->id);
                   });

            $user_input = User::factory()->raw();

            $browser->with('@modal', function ($browser) use ($user_input) {
                $browser->with('@livestream-registration-form', function ($browser) use ($user_input) {
                    $browser->waitFor('@name')
                        ->type('@name', Arr::get($user_input, 'name'))
                        ->type('@email', Arr::get($user_input, 'email'))
                        ->click('@next')
                        ->waitFor('@finish')
                        ->click('@finish');
                });
            });

            $browser->within(new Feedback(), function ($browser) {
                $browser->assertFeedbackContains('Registration Complete');
            });

            $livestream_registration = LivestreamRegistration::all()->last();

            $this->assertEquals($livestream_registration->user->email, Arr::get($user_input, 'email'));
            $user = $livestream_registration->user;
            $user->password = bcrypt('password');
            $user->save();
            $user->refresh();

            $message = $this->faker->sentence();

            $browser->with('@modal', function ($browser) use ($livestream) {
                $browser->with('@livestream-registration-complete', function ($browser) use ($livestream) {
                    $browser->assertSee($livestream->name.' Registration Complete')
                        ->click('@close');
                });
            })
           ->with('@livestream-'.$livestream->id, function ($browser) use ($livestream) {
               $browser->click('@join-livestream-'.$livestream->id);
           })
           ->waitForRoute('livestreams.view', ['id' => $livestream->id])
           ->with('@chat-room-'.$livestream->chat_room, function ($browser) {
               $browser->pause(500)
                   ->assertMissing('@message')
                   ->assertVisible('@login-notice')
                   ->click('@login');
           })
           ->waitForRoute('login')
            ->waitFor('@login-email', 20)
            ->type('@login-email', $user->email)
            ->type('@login-password', 'password')
            ->click('@submit-login-button')
            ->pause(500)
            ->within(new Feedback(), function ($browser) {
                $browser->assertFeedbackContains('Login Successful');
            })
           ->waitForRoute('livestreams.view', ['id' => $livestream->id])
           ->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($message) {
               $browser->pause(500)
                   ->assertVisible('@message')
                   ->assertMissing('@login-notice')
                   ->type('@message', $message)
                  ->keys('@message', ['{enter}'])
                  ->pause(500);
           });

            $chat = Chat::all()->last();
            $this->assertEquals($chat->message, $message);

            $browser->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($message, $chat) {
                $browser->waitFor('@chat')
                    ->pause(500)
                    ->assertSeeIn('@chat-message-'.$chat->id, $message);
            });
        });
    }

    public function test_the_popout_chat_can_be_loaded()
    {
        $this->browse(function ($browser, $guest) {
            $livestream = Livestream::factory()->privateChat()->create();
            $admin = User::factory()->create();
            $admin->addRole('livestreams-manager');
            $user = User::factory()->create();

            $livestream->registerUser($user);
            $url = LivestreamRegistration::all()->last()->url;

            $message1 = $this->faker->sentence();
            $message2 = $this->faker->sentence();

            // login mod
            $browser->visit(new Login())
                    ->loginUser($admin)
                    ->visitRoute('livestreams.view', ['id' => $livestream->id])
                    ->waitFor('@chat-room-'.$livestream->chat_room)
                    ->with('@chat-room-'.$livestream->chat_room, function ($browser) {
                        $browser->pause(1500) // for the feedback to disappear
                            ->click('@hide-chat')
                            ->pause(500)
                            ->assertMissing('@chat')
                            ->click('@show-chat')
                            ->pause(500)
                            ->assertVisible('@chat')
                            ->click('@popout-chat');
                    });

            $window = collect($browser->driver->getWindowHandles())->last();
            $original_window = collect($browser->driver->getWindowHandles())->first();
            $browser->driver->switchTo()->window($window);

            $browser->waitFor('@chat-room-'.$livestream->chat_room);

            // login guest
            $guest->visit($url)
                    ->waitFor('@chat-room-'.$livestream->chat_room)
                    ->with('@chat-room-'.$livestream->chat_room, function ($guest) {
                        $guest->pause(1500) // for the feedback to disappear
                            ->click('@hide-chat')
                            ->pause(500)
                            ->assertMissing('@chat')
                            ->click('@show-chat')
                            ->pause(500)
                            ->assertVisible('@chat')
                            ->click('@popout-chat');
                    });

            $window = collect($guest->driver->getWindowHandles())->last();
            $original_guest = collect($guest->driver->getWindowHandles())->first();
            $guest->driver->switchTo()->window($window);

            $guest->waitFor('@chat-room-'.$livestream->chat_room)
                  ->with('@chat-room-'.$livestream->chat_room, function ($guest) use ($message1) {
                      $guest->waitFor('@message')
                            ->pause(250)
                            ->type('@message', $message1)
                            ->keys('@message', ['{enter}'])
                            ->pause(500);
                  });

            $chat1 = Chat::all()->last();

            $browser->assertVisible('@chat-message-'.$chat1->id)
                    ->assertSee($chat1->message)
                    ->assertSee($message1)
                      ->with('@chat-room-'.$livestream->chat_room, function ($guest) use ($message2) {
                          $guest->type('@message', $message2)
                                ->keys('@message', ['{enter}'])
                                ->pause(500);
                      });

            $chat2 = Chat::all()->last();

            $browser->driver->switchTo()->window($original_window);

            $browser->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($chat1, $chat2) {
                $browser->click('@show-chat')
                    ->pause(500)
                    ->assertVisible('@chat-message-'.$chat1->id)
                    ->assertVisible('@chat-message-'.$chat1->id)
                    ->assertSee($chat1->message)
                    ->assertSee($chat2->message);
            });
        });
    }

    public function test_a_user_can_view_a_listream_with_private_chat()
    {
        $this->browse(function ($browser) {
            $livestream = Livestream::factory()->create([
                'chat_mode' => 'private',
                'can_register' => 0,
            ]);

            $browser->loginAs(User::find(1))
                ->visit(route('livestreams.view', ['id' => $livestream->id]))
                ->pause(2000)
                ->assertRouteIs('livestreams.view', ['id' => $livestream->id])
                ->waitFor('@player-livestream-'.$livestream->id)
                ->waitFor('@chat-room-'.$livestream->chat_room);
        });
    }

    public function test_a_guest_can_register_for_a_livestream_from_in_the_chat()
    {
        $this->browse(function ($browser) {
            $livestream = Livestream::factory()->create([
                'chat_mode' => 'private',
                'can_register' => true,
                'unlisted' => false,
            ]);

            $logged_in = count($browser->driver->findElements(WebDriverBy::id('user-menu')));

            if ($logged_in) {
                $browser->click('@user-menu')
                        ->pause(250)
                        ->clickAndWaitForReload('@logout-button');
            }

            $browser->visit('/live')
                    ->waitFor('@paginator-upcoming-events', 20)
                    ->with('@paginator-upcoming-events', function ($browser) use ($livestream) {
                        $browser->type('@paginator-search', $livestream->name);
                    })
                    ->waitFor('@livestream-'.$livestream->id)
                    ->with('@livestream-'.$livestream->id, function ($browser) use ($livestream) {
                        $browser->waitFor('@watch-livestream-'.$livestream->id)
                            ->pause(500)
                            ->click('@watch-livestream-'.$livestream->id);
                    })
                    ->waitForRoute('livestreams.view', ['id' => $livestream->id])
                    ->waitFor('@player-livestream-'.$livestream->id)
                    ->waitFor('@chat-room-'.$livestream->chat_room)
                    ->with('@chat-room-'.$livestream->chat_room, function ($browser) {
                        $browser->assertSee('Register Now')
                            ->click('@register-now');
                    });

            $user_input = User::factory()->raw();

            $browser->with('@modal', function ($browser) use ($user_input) {
                $browser->with('@livestream-registration-form', function ($browser) use ($user_input) {
                    $browser->waitFor('@name')
                        ->type('@name', Arr::get($user_input, 'name'))
                        ->type('@email', Arr::get($user_input, 'email'))
                        ->click('@next')
                        //->waitFor('@start-year-'.now()->addYears(1)->format('Y'))
                        //->click('@start-year-'.now()->addYears(1)->format('Y'))
                        //->click('@grade-10')
                        //->click('@next')
                        ->waitFor('@finish')
                        ->click('@finish');
                });
            });

            $browser->within(new Feedback(), function ($browser) {
                $browser->assertFeedbackContains('Registration Complete');
            });

            $browser->with('@modal', function ($browser) use ($livestream) {
                $browser->waitFor('@livestream-registration-complete')
                    ->assertMissing('@livestream-registration-form')
                    ->with('@livestream-registration-complete', function ($browser) use ($livestream) {
                        $browser->assertSee($livestream->name.' Registration Complete')
                            ->click('@close');
                    });
            })
                ->pause(500) // fade transition
                ->assertMissing('@livestream-registration')
                ->assertMissing('@modal');

            $livestream_registration = LivestreamRegistration::all()->last();
            $attendee = $livestream_registration->user;
            $this->assertEquals(Arr::get($user_input, 'email'), $attendee->email);
            $this->assertEquals($livestream_registration->user->email, $attendee->email);

            $message = Arr::get(Chat::factory()->raw(), 'message');
            $this->assertNotNull($message);

            $browser->visit($livestream_registration->url)
                    ->pause(500)
                    ->assertAuthenticatedAs($attendee)
                    ->pause(500)
                    //->visit($livestream_registration->url)
                    ->assertPathIs('/livestreams/'.$livestream->id)
                    ->waitFor('@player-livestream-'.$livestream->id)
                    ->waitFor('@chat-room-'.$livestream->chat_room)
                    ->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($message) {
                        $browser->type('@message', $message)
                              ->keys('@message', ['{enter}'])
                              ->pause(500);
                    });

            $chat_message = Chat::all()->last();

            $browser->with('@chat-room-'.$livestream->chat_room, function ($browser) use ($chat_message) {
                $browser->waitFor('@chat-message-'.$chat_message->id)
                    ->assertSeeIn('@chat', $chat_message->message);
            });
        });
    }
}
