<?php
/**
 * Copyright 2016 David Vivier on behalf of Smartic.ca
 * 
 * This file is part of the Smarticops Package
 * 
 * License : MIT
 * 
 * @author David Vivier
 */

use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

use Dvivier\Smarticops\User;
use Dvivier\Smarticops\Role;
use Dvivier\Smarticops\Permission;

class UserTest extends TestCase
{
    
    use DatabaseMigrations;
    
    //public static function setUpBeforeClass() {
    public function setup() {
        
        parent::setup();
        $this->seed();
        Auth::login(User::find(1));
        
        $this->user = factory(User::class)->create([
                                                    'first_name' => 'Stanley',
                                                    'last_name'  => 'Kubrick'
                                                    ]);
                                                    
        $this->roleStudent = factory(Role::class)->create( [
                                                                'name' => 'Student'
                                                                ]);
        
        $this->roleTeacher = factory(Role::class)->create( [
                                                                'name' => 'Teacher'
                                                                ]);
        
        $perm1 = new Permission();
        $perm1->code = 'world.dominate';
        $perm1->save();
        
        $perm2 = new Permission();
        $perm2->code = 'world.create';
        $perm2->save();
    }
    
    public function testFullName() {
        
        $user = $this->user;
        
        $this->assertEquals('Stanley Kubrick', $user->fullName());
        
    }
    
    public function testSoftDeleteUser() {
        
        $user = $this->user;
        
        $this->seeInDatabase( 'users', [
                                                'id'         => $user->id,
                                                'deleted_at' => null 
                                                ]);
        
        $user->delete(); // soft delete !
        
        $this->seeInDatabase(       'users', [
                                                'id'         => $user->id,
                                                ])
                ->notSeeInDatabase( 'users', [
                                                'id'         => $user->id,
                                                'deleted_at' => null 
                                                ]);
    }
    
    
    
    
    public function testAssignRole() {
    
    // init    
        $user = $this->user;
        $role = $user->role;
        // at the beginning the user has no role
        $this->assertNull($role);
        
        $roleStudent = $this->roleStudent;
        
        $this->assertEquals('Student', $roleStudent->name);
        
        $this->assertFalse($user->assignRole(null));
        
    // assign role by object
        
        $res = $user->assignRole($roleStudent);

        //var_dump($roleStudent->users);
        //var_dump($user->role);
        
        
        //$this->assertTrue($res);
        
        //$this->assertEquals('Student', $user->role->getName());
        
        
        //$this->assertTrue($user->hasRole('Student'));
        //$this->assertFalse($user->hasRole('Teacher'));
        
        $this->seeInDatabase('users_roles', [
                                                'user_id' => $user->id,
                                                'role_id' => $roleStudent->id,
                                                'created_by'    => 1,
                                                ]);
        
        
        
    // assign by string
        //print_r('assign by string');
        
        $roleTeacher = $this->roleTeacher;
        $res = $user->assignRole($roleTeacher->name);
        
        
        //$this->assertTrue($res);
        
        // we se the two associations in the database        
        $this->seeInDatabase('users_roles', [
                                        'user_id' => $user->id,
                                        'role_id' => $roleStudent->id
                                        ]);
        $this->seeInDatabase('users_roles', [
                                            'user_id' => $user->id,
                                            'role_id' => $roleTeacher->id
                                            ]);
        
        //$this->assertTrue($user->hasRole('Teacher'));
        //$this->assertFalse($user->hasRole('Student'));
        
    }
    
    
    public function testGetRoles() {
        
        $user = $this->user;
        $roleStudent = $this->roleStudent;
        $roleTeacher = $this->roleTeacher;
        
        
        $res = $user->assignRole('Teacher');
        
        //$this->assertTrue($res);
        
        $roles = $user->getRoles();
        
        $this->assertEquals(['Teacher'], $roles);
        
        // adding a 2nd role
        $res = $user->assignRole('Student');
        
        //$this->assertTrue($res);
        
        $this->seeInDatabase('users_roles', [
                                        'user_id' => $user->id,
                                        'role_id' => $roleStudent->id
                                        ]);
        $this->seeInDatabase('users_roles', [
                                            'user_id' => $user->id,
                                            'role_id' => $roleTeacher->id
                                            ]);
        
        
        $roles = $user->getRoles();
        //var_dump($roles);
        $this->assertEquals(['Teacher', 'Student'], $roles);
        
    }
    
    public function testHasRole() {
        //print('\ntestHasRole()');
        $user = $this->user;
        $user->assignRole('Teacher');
        
        $roleTeacher = $this->roleTeacher;
        // first, check if the association is in the database (theorically yes)
        $this->seeInDatabase('users_roles', [
                                            'user_id' => $user->id,
                                            'role_id' => $roleTeacher->id
                                            ]);
        
        // then test the function
        $this->assertTrue($user->hasRole('Teacher'));
        
    }
    
    public function testPermissionsAssignedByRoles() {
        //print_r('testPermissionsAssignedByRoles');
        
        
        // initialisation
        $user = $this->user;
        $roleStudent = $this->roleStudent;
        
        $this->assertFalse($user->is('Student'));
        $this->assertFalse($roleStudent->hasPermission('world.dominate', true));
        $this->assertFalse($user->hasPermission('world.dominate', true));
        $this->assertFalse($user->hasPermission('world.create', true));
        
        // preparation : we give 2 permissions to the role
        $roleStudent->givePermission('world.dominate');
        $roleStudent->givePermission('world.create');
        $this->assertTrue($roleStudent->hasPermission('world.dominate', true));
        $this->assertTrue($roleStudent->hasPermission('world.create', true));
        
        // test : we assign the role to the user
        //      and we check he also got the role's permissions
        $user->assignRole('Student', true);
        $this->assertTrue($user->is('Student'));
        $this->assertTrue($user->hasPermission('world.dominate', true));
        $this->assertTrue($user->hasPermission('world.create', true));
        
        
    }
    
    public function testRevokeRole_single() {
        // assign a role, then remove it
        
        $user = $this->user;
        
        $this->assertFalse($user->hasRole('Teacher'));
        
        $user->assignRole('Teacher');
        
        // first check that the user really has the role
        $this->assertTrue($user->hasRole('Teacher'));
        
        // then test the method
        $res = $user->revokeRole('Teacher');
        
        $this->assertTrue($res);
        
        // did he lose the role ?
        $this->assertFalse($user->hasRole('Teacher'));
        
        
        
    }
    
    public function testRevokeRole_multiple() {
        // assign two roles, then removes one, then remove the other one
        
        $user = $this->user;
        $roleStudent = $this->roleStudent;
        $roleTeacher = $this->roleTeacher;
        
        
        $user->assignRole('Student');
        $user->assignRole('Teacher');
        
        $this->assertTrue($user->is('Student'));
        $this->assertTrue($user->is('Teacher'));
        
        $user->revokeRole('Teacher');
        
        // now he is only a simple student
        $this->assertTrue($user->is('Student'));
        $this->assertFalse($user->is('Teacher'));
   
        $user->revokeRole('Student');
        
        // and now he's nothing
        $this->assertFalse($user->is('Student'));
        $this->assertFalse($user->is('Teacher'));
   
    }
    
    public function testRevokeRole_noexist() {
        
        // testing a role which doesn't exist
        
        $user = $this->user;
        
        $this->assertFalse($user->hasRole('MasterOfTheUniverse'));
        
    }
    
    public function testRevokeAllRoles() {
        
        $user = $this->user;
        $roleStudent = $this->roleStudent;
        $roleTeacher = $this->roleTeacher;
        
        
        $user->assignRole('Student');
        $user->assignRole('Teacher');
        
        $user->revokeAllRoles();
        
        $this->assertFalse($user->is('Student'));
        $this->assertFalse($user->is('Teacher'));
    }
    
    
    public function testScopeHavingRole() {

        // preparation : 2 students and 1 teacher
        $student1 = User::create();
        $student1->assignRole('Student');
        $student2 = User::create();
        $student2->assignRole('Student');
        
        $teacher = User::create();
        $teacher->assignRole('Teacher');
        
        
        // test
        $students = User::havingRole('Student');
        //var_dump($students);
        $this->assertEquals(2, count($students->get()));
        $student1_test = $students->first();
        $this->assertEquals($student1->id, $student1_test->id);
    }
    
    
    
    
    public function testGivePermission() {
        
        
        $user = $this->user;
        
        $user->givePermission('world.dominate');
        
        $code = 'world.dominate';
        
        $this->seeInDatabase( 'permissions', [
                                                'code' => $code
                                                ] );
        
        $permission = DB::select( 'SELECT * 
                                        FROM permissions
                                        WHERE code = ?', [$code] )[0];
        
        $this->seeInDatabase( 'users_permissions', [
                                                'user_id'        => $user->id,
                                                'permission_id'  => $permission->id,
                                                'value'          => true,
                                                'created_by'     => 1,
                                                    ]);

        $user->givePermission('world.dominate', false);
        
        $this->seeInDatabase( 'users_permissions', [
                                                'user_id'        => $user->id,
                                                'permission_id'  => $permission->id,    
                                                'value'          => false,
                                                'created_by'     => 1,
                                                    ]);
        
    }
    
    
    public function testHasPermission() {
       
        $user = $this->user;
        
        $user->givePermission('world.dominate');
        $user->givePermission('world.destroy', false);
        //print_r('1- ');
        $this->assertFalse($user->hasPermission('world.create', true));
        $this->assertTrue($user->hasPermission('world.dominate', true));
        $this->assertFalse($user->hasPermission('world.destroy', true));
        
        $user->givePermission('world.dominate', false);
        //print_r('2- ');
        $this->assertFalse($user->hasPermission('world.dominate', true));
        
    }
    
    public function testRemovePermission() {
        
        $user = $this->user;
        
        $user->givePermission('world.dominate');
        
        $this->assertTrue($user->hasPermission('world.dominate', true));
        
        $permission = DB::select( 'SELECT * 
                                        FROM permissions
                                        WHERE code = ?', [ 'world.dominate' ] )[0];
        
        $this->seeInDatabase( 'users_permissions', [
                                                'user_id'        => $user->id,
                                                'permission_id'  => $permission->id,
                                                'value'          => true
                                                    ]);
        
        $user->removePermission('world.dominate');
        
        $this->assertFalse($user->hasPermission('world.dominate', true));
        
        
        $this->notSeeInDatabase( 'users_permissions', [
                                                'user_id'        => $user->id,
                                                'permission_id'  => $permission->id,
                                                    ]);

        
    }
    
    
    
}

