<?php

namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Mail;

use App\Models\Inquiry;
use App\Models\Livestream;
use App\Models\User;
use App\Models\Role;

use Tests\Unit\PermissionsTestTrait;
use Tests\Unit\FieldLinkTestTrait;

use App\Mail\LivestreamRegistered;
use App\Mail\LivestreamModeratorAdded;

class LivestreamTest extends TestCase
{
    use WithFaker;
    use PermissionsTestTrait;
    use FieldLinkTestTrait;

    protected function getClassname()
    {
        return 'livestream';
    }

    protected function getLinkFields()
    {
        return [
            'description',
        ];
    }

    protected function getModel()
    {
        return Livestream::factory()->create();
    }

    public function test_a_livestream_can_belong_to_many_inquiry_users()
    {
        $inquiry = Inquiry::factory()->create();
        $livestream = Livestream::factory()->create();
        $inquiry->saveLivestreams(['livestream' => $livestream]);

        $livestream->refresh();
        $this->assertEquals(1, $livestream->inquiryUsers()->count());
        $this->assertEquals($inquiry->user->id, $livestream->inquiryUsers()->first()->id);
    }

    public function test_a_livestream_has_a_full_slug_attribute()
    {
        $livestream = Livestream::factory()->create();
        $this->assertNotNull($livestream->full_slug);
        $this->assertEquals('livestreams/'.$livestream->id, $livestream->full_slug);
    }

    public function test_a_livestream_has_a_date_attribute()
    {
        $livestream = Livestream::factory()->create();
        $this->assertNotNull($livestream->date);
        $this->assertEquals($livestream->start_date->timezone('America/Vancouver')->format('l F j, Y g:i a'), $livestream->date);
    }

    public function test_a_livestream_can_have_many_roles()
    {
        $livestream = Livestream::factory()->create();
        $role = Role::factory()->create();

        $livestream->createPermission('view', $role);

        $livestream->refresh();

        $this->assertNotNull($livestream->roles);
        $this->assertEquals(1, $livestream->roles->count());
        $this->assertTrue($livestream->roles->contains('id', $role->id));

        $user = User::factory()->create();
        $user->addRole($role);
        $user->refresh();
        $this->assertTrue($user->can('view', $livestream));
    }

    public function test_a_livestream_can_have_many_users()
    {
        $livestream = Livestream::factory()->create();
        $user = User::factory()->create();

        $livestream->createPermission('view', $user);

        $livestream->refresh();

        $this->assertNotNull($livestream->users);
        $this->assertEquals(1, $livestream->users->count());
        $this->assertTrue($livestream->users->contains('id', $user->id));

        $this->assertTrue($user->can('view', $livestream));
    }

    public function test_a_livestream_can_have_many_moderators()
    {
        $livestream = Livestream::factory()->create();
        $user = User::factory()->create();
        $livestream->createPermission('moderate', $user);

        $this->assertNotNull($livestream->moderators);
        $this->assertEquals(1, $livestream->moderators->count());
        $this->assertTrue($livestream->moderators->contains('id', $user->id));
    }

    public function test_a_livestream_can_register_a_user()
    {
        $user = User::factory()->create();
        $livestream = Livestream::factory()->create();

        $livestream->registerUser($user);

        $user->refresh();
        $livestream->refresh();

        $this->assertEquals(1, $livestream->users()->count());
        $this->assertTrue($livestream->users()->get()->contains('id', $user->id));
        $this->assertTrue($user->can('view', $livestream));
    }

    public function test_a_livestream_can_register_a_user_by_user_id()
    {
        $user = User::factory()->create();
        $livestream = Livestream::factory()->create();

        $livestream->registerUser([
            'user_id' => $user->id,
        ]);

        $user->refresh();
        $livestream->refresh();

        $this->assertEquals(1, $livestream->users()->count());
        $this->assertTrue($livestream->users()->get()->contains('id', $user->id));
        $this->assertTrue($user->can('view', $livestream));
    }

    public function test_a_livestream_can_register_a_user_by_name_and_email()
    {
        $livestream = Livestream::factory()->create();
        $name = $this->faker->name;
        $email = $this->faker->unique()->safeEmail;

        $livestream->registerUser([
            'name' => $name,
            'email' => $email,
        ]);

        $user = User::all()->last();
        $this->assertEquals($email, $user->email);
        $livestream->refresh();

        $this->assertEquals(1, $livestream->users()->count());
        $this->assertTrue($livestream->users()->get()->contains('id', $user->id));
        $this->assertTrue($user->can('view', $livestream));
    }

    public function test_a_livestream_can_register_a_user_without_sending_a_confirmation_email()
    {
        $user = User::factory()->create();
        $user2 = User::factory()->create();
        $livestream = Livestream::factory()->create();

        Mail::fake();

        $livestream->registerUser($user2, true);

        Mail::assertNotQueued(LivestreamRegistered::class, function ($mail) use ($user2) {
            return $mail->hasTo($user2->email);
        });

        $livestream->registerUser($user);

        Mail::assertQueued(LivestreamRegistered::class, function ($mail) use ($user) {
            return $mail->hasTo($user->email);
        });

        $user->refresh();
        $livestream->refresh();

        $this->assertEquals(2, $livestream->users()->count());
        $this->assertTrue($livestream->users()->get()->contains('id', $user->id));
        $this->assertTrue($user->can('view', $livestream));

        $this->assertTrue($livestream->users()->get()->contains('id', $user2->id));
        $this->assertTrue($user2->can('view', $livestream));
    }

    /*
    public function livestreams_can_be_retreived_and_filtered_by_permissions()
    {
        $user = User::factory()->create();

        $role = Role::factory()->create();
        $role_user = User::factory()->create();
        $role_user->addRole($role);
        $role_user->refresh();

        $livestream = Livestream::factory()->create([
            'unlisted' => true,
        ]);

        $this->assertFalse(Livestream::getLivestreams()->contains('name', $livestream->name));

        $livestream->createPermission('view', $user);
        $livestream->refresh();
        $this->assertTrue($livestream->users->contains('id', $user->id));

        $this->signIn(User::factory()->create());

        $this->assertFalse(Livestream::getLivestreams()->contains('name', $livestream->name));

        $this->signIn($user);

        $this->assertTrue(Livestream::getLivestreams()->contains('name', $livestream->name));

        $this->signIn($role_user);

        $this->assertFalse(Livestream::getLivestreams()->contains('name', $livestream->name));

        $livestream->refresh();
        $livestream->createPermission('view', $role);
        $this->assertTrue($livestream->roles->contains('id', $role->id));

        $this->assertTrue(Livestream::getLivestreams()->contains('name', $livestream->name));

        $inquiry = Inquiry::factory()->create();
        $inquiry_user = $inquiry->user;

        $this->signIn($inquiry_user);
        $this->assertFalse(Livestream::getLivestreams()->contains('name', $livestream->name));

        $inquiry->saveLivestreams(['livestream' => $livestream]);

        $this->assertTrue(Livestream::getLivestreams()->contains('name', $livestream->name));
    }
     */

    public function test_a_livestream_has_a_register_action()
    {
        $livestream = Livestream::factory()->create();
        $user = User::factory()->create();

        $this->signIn($user);

        $this->assertNotNull($livestream->actions);
        $this->assertTrue($livestream->actions->keys()->contains('register'));
        $this->assertFalse($livestream->actions->keys()->contains('registered'));

        $livestream->registerUser($user);

        $livestream->refresh();

        $this->assertFalse($livestream->actions->keys()->contains('register'));
        $this->assertTrue($livestream->actions->keys()->contains('registered'));
    }

    public function test_saving_moderators_doesnt_resend_an_email_invite()
    {
        $mod1 = User::factory()->create();
        $mod2 = User::factory()->create();
        $livestream = Livestream::factory()->create();

        $input = [
            'moderators' => [
                $mod1,
                $mod2,
            ],
        ];

        Mail::fake();

        $livestream->saveModerators($input);
        $livestream->refresh();
        $this->assertTrue($mod1->can('moderate', $livestream));
        $this->assertTrue($mod2->can('moderate', $livestream));

        Mail::assertQueued(LivestreamModeratorAdded::class, function ($mail) use ($mod1) {
            return $mail->hasTo($mod1->email);
        });

        Mail::assertQueued(LivestreamModeratorAdded::class, function ($mail) use ($mod2) {
            return $mail->hasTo($mod2->email);
        });

        Mail::fake();

        $livestream->saveModerators($input);
        $livestream->refresh();
        $this->assertTrue($mod1->can('moderate', $livestream));
        $this->assertTrue($mod2->can('moderate', $livestream));

        Mail::assertNotQueued(LivestreamModeratorAdded::class, function ($mail) use ($mod1) {
            return $mail->hasTo($mod1->email);
        });

        Mail::assertNotQueued(LivestreamModeratorAdded::class, function ($mail) use ($mod2) {
            return $mail->hasTo($mod2->email);
        });

        $livestream->saveModerators([
            'moderators' => [
                $mod1,
            ]
        ]);

        $livestream->refresh();
        $mod1->refresh();
        $mod2->refresh();
        $this->assertTrue($mod1->can('moderate', $livestream));
        $this->assertFalse($mod2->can('moderate', $livestream));
    }

    public function test_managers_and_mods_can_view_livestreams()
    {
        $user = User::factory()->create();
        $livestream = Livestream::factory()->create();

        $this->assertFalse($user->can('view', $livestream));
        $user->addRole('livestreams-manager');
        $user->refresh();

        $this->assertTrue($user->can('view', $livestream));

        $user2 = User::factory()->create();

        $this->assertFalse($user2->can('view', $livestream));

        $livestream->createPermission('moderate', $user2);

        $user2->refresh();

        $this->assertTrue($user->can('view', $livestream));
    }

    public function test_any_user_can_chat_in_a_public_event()
    {
        $user = User::factory()->create();
        $livestream = Livestream::factory()->create([
            'unlisted' => false,
        ]);

        $this->assertTrue($user->can('chat', $livestream));

        $livestream->unlisted = true;
        $livestream->save();

        $livestream->refresh();
        $user->refresh();

        $this->assertFalse($user->can('chat', $livestream));

        $livestream->registerUser($user);

        $livestream->refresh();
        $user->refresh();
        $this->assertTrue($user->can('chat', $livestream));

        $this->assertTrue($user->can('chat', $livestream));
    }

    public function test_a_livestream_manage_can_moderate()
    {
        $user = User::factory()->create();
        $user->addRole('livestreams-manager');
        $user->refresh();
        $livestream = Livestream::factory()->create();
        $this->assertTrue($user->can('moderate', $livestream));
    }
}
