<?php

namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

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

use Laravel\Socialite;

class UserTest extends TestCase
{
    use WithFaker;

    public function test_a_user_can_have_many_roles()
    {
        $user = User::factory()->create();
        $role = Role::factory()->create();

        $user->roles()->attach($role);

        $user->refresh();

        $this->assertNotNull($user->roles);
        $this->assertTrue($user->roles->contains('id', $role->id));
    }


    public function test_a_user_can_add_a_role()
    {
        $user = User::factory()->create();
        $role = Role::factory()->create();

        $user->addRole($role);

        $user->refresh();

        $this->assertTrue($user->roles->contains('id', $role->id));
    }

    public function test_a_user_can_remove_a_role()
    {
        $user = User::factory()->create();
        $role = Role::factory()->create();

        $user->addRole($role);

        $user->refresh();
        $this->assertTrue($user->roles->contains('id', $role->id));

        $user->removeRole($role);

        $user->refresh();
        $this->assertFalse($user->roles->contains('id', $role->id));
    }

    public function test_a_user_can_add_role_by_name()
    {
        $user = User::factory()->create();
        $role = Role::factory()->create();

        $user->addRole($role->name);

        $user->refresh();

        $this->assertTrue($user->roles->contains('id', $role->id));
    }

    public function test_a_user_can_check_if_they_have_a_role()
    {
        $user = User::factory()->create();
        $role = Role::factory()->create();

        $this->assertFalse($user->hasRole($role));
        // check by name
        $this->assertFalse($user->hasRole($role->name));
        // check by id
        $this->assertFalse($user->hasRole($role->id));

        $user->addRole($role);
        $user->refresh();

        $this->assertTrue($user->hasRole($role));
        // check by name
        $this->assertTrue($user->hasRole($role->name));
        // check by id
        $this->assertTrue($user->hasRole($role->id));
    }

    public function test_a_role_can_be_found_by_name_with_dashes_in_the_title()
    {
        $role = Role::factory()->create([
            'name' => Str::random(4).'-'.Str::random(4),
        ]);

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

        $this->assertTrue($user->hasRole($role->name));
    }


    public function test_an_admin_user_has_all_roles()
    {
        $role = Role::factory()->create();
        $admin_role = Role::where('name', 'admin')->first();
        $this->assertInstanceOf(Role::class, $admin_role);

        $admin_user = User::whereHas('roles', function ($query) {
            $query->where('name', 'admin');
        })->first();

        $this->assertInstanceOf(User::class, $admin_user);

        $this->assertTrue($admin_user->hasRole('admin'));
        $this->assertTrue($admin_user->hasRole($role));
    }


    public function test_a_user_can_be_created_from_google()
    {
        $id = '113984752438530878390';
        $google_data = new Socialite\Two\User();
        $google_data->token = $this->faker->sha256;
        $google_data->expiresIn = 3599;
        $google_data->id = $id;
        $google_data->nickname = null;
        $google_data->name = 'Mike Minckler';
        $google_data->email = 'mike.minckler@brentwood.ca';
        $google_data->avatar = 'https://lh3.googleusercontent.com/a-/AOh14GhW2zbSQ4LIdT_pDThpx4MzSX9BnE4YlR-Ewib0EEc';
        $google_data->user =  [
                'sub' => $id,
                'name' => 'Mike Minckler',
                'given_name' => 'Mike',
                'family_name' => 'Minckler',
                'profile' => 'https://plus.google.com/113984752438530878390',
                'picture' => 'https://lh3.googleusercontent.com/a-/AOh14GhW2zbSQ4LIdT_pDThpx4MzSX9BnE4YlR-Ewib0EEc',
                'email' => 'mike.minckler@brentwood.ca',
                'email_verified' => true,
                'locale' => 'en',
                'hd' => 'brentwood.ca',
                'id' => $id,
                'verified_email' => true,
                'link' => 'https://plus.google.com/113984752438530878390',
            ];
        $google_data->avatar_original = 'https://lh3.googleusercontent.com/a-/AOh14GhW2zbSQ4LIdT_pDThpx4MzSX9BnE4YlR-Ewib0EEc';

        $user = User::createOrUpdateFromGoogle($google_data);

        $this->assertInstanceOf(User::class, $user);
        $this->assertEquals($google_data->getId(), $user->oauth_id);
        $this->assertEquals($google_data->getEmail(), $user->email);
        $this->assertEquals($google_data->getName(), $user->name);
        $this->assertEquals($google_data->getAvatar(), $user->avatar);
    }

    public function test_a_user_can_be_found_or_created_by_email()
    {
        $name = $this->faker->name;
        $email = $this->faker->safeEmail;

        $input = [
            'name' => $name,
            'email' => $email,
        ];

        $user = User::findOrCreateByEmail($input);

        $this->assertInstanceOf(User::class, $user);

        $this->assertEquals($name, $user->name);
        $this->assertEquals($email, $user->email);

        $user2 = User::findOrCreateByEmail($input);

        $this->assertEquals($user->id, $user2->id);
    }

    public function test_a_user_has_many_inquiries()
    {
        $inquiry = Inquiry::factory()->create();
        $user = $inquiry->user;
        $this->assertInstanceOf(User::class, $user);

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

    public function test_a_user_can_have_many_whispers()
    {
        $user = User::factory()->create();
        $chat = Chat::factory()->create();
        $user->whispers()->attach($chat);

        $this->assertEquals(1, $user->whispers->count());
        $this->assertTrue($user->whispers->contains('message', $chat->message));
    }

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

        $user->registerForLivestream($livestream);

        $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_user_can_have_many_livestream_registrations()
    {
        $livestream = Livestream::factory()->create();
        $user = User::factory()->create();

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

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

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

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

    public function test_a_user_can_have_a_staff_profile()
    {
        $staff_profile = StaffProfile::factory()->create();
        $this->assertNotNull($staff_profile->user_id);
        $this->assertNotNull($staff_profile->user);
        $user = $staff_profile->user;
        $this->assertInstanceOf(User::class, $user);
        $this->assertNotNull($user->staffProfile);
        $this->assertInstanceOf(StaffProfile::class, $user->staffProfile);
        $this->assertEquals($staff_profile->id, $user->staffProfile->id);
    }

    public function test_a_user_has_a_first_name_and_last_name_attribute()
    {
        $first = $this->faker->word;
        $last = $this->faker->word;
        $third = $this->faker->word;
        $full_name = $first.' '.$last;

        $user = User::factory()->create([
            'name' => '',
        ]);

        $this->assertEquals('', $user->first_name);
        $this->assertEquals('', $user->last_name);

        $user = User::factory()->create([
            'name' => $first,
        ]);

        $this->assertEquals($first, $user->first_name);
        $this->assertEquals('', $user->last_name);

        $user = User::factory()->create([
            'name' => $full_name,
        ]);

        $this->assertEquals($first, $user->first_name);
        $this->assertEquals($last, $user->last_name);

        $user->name = $first.' '.$last.' '.$third;
        $user->save();
        $user->refresh();

        $this->assertEquals($first, $user->first_name);
        $this->assertEquals($last.' '.$third, $user->last_name);
    }

}
