<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

use App\Models\User;
use App\Models\Page;
use App\Models\Role;

class LoginTest extends TestCase
{
    public function test_the_login_view_can_be_loaded()
    {
        $this->get(route('login'))
            ->assertSuccessful();
    }

    public function test_if_a_user_is_logged_in_they_are_redirected()
    {
        $this->signInAdmin();
        $this->get(route('login'))
            ->assertStatus(302);
    }

    public function test_a_user_can_login()
    {
        $user = User::factory()->create([
            'password' => bcrypt('password'),
        ]);

        $this->json('POST', route('login'), ['email' => $user->email, 'password' => 'password'])
             ->assertJsonFragment([
                'redirect' => '/?success=Login%20Successful',
             ])
            ->assertSessionHas('timeout');
    }

    public function test_a_user_is_redirected_to_google_auth_when_trying_to_login_to_google()
    {
        $this->get('/login/google')
            ->assertRedirect();
    }

    public function test_an_intended_url_can_be_set()
    {
        $url = route('livestreams.index');
        $this->assertNull(session()->get('url.intended'));
        $this->json('POST', route('intended-url'), ['url' => $url])
             ->assertSuccessful();
        $this->assertNotNull(session()->get('url.intended'));
        $this->assertEquals($url, session()->get('url.intended'));
    }

    public function test_a_timeout_check_can_be_made()
    {
        $user = User::factory()->create([
            'password' => bcrypt('password'),
        ]);

        $this->json('POST', route('timeout-check'))
             ->assertStatus(401);

        $this->json('POST', route('login'), [
            'email' => $user->email,
            'password' => 'password',
        ])
        ->assertSuccessful()
        ->assertSessionHas('timeout');

        $this->withoutExceptionHandling();
        $this->json('POST', route('timeout-check'))
             ->assertSuccessful()
            ->assertJsonFragment([
                'success' => 'Session Valid',
            ])
             ->assertSessionHas('timeout');

        session()->put('timeout', now()->subSeconds(1));

        $this->json('POST', route('timeout-check'), ['activity' => true])
             ->assertSuccessful()
            ->assertJsonFragment([
                'success' => 'Session Updated',
            ]);

        sleep(2);

        $this->assertGreaterThan(now(), session()->get('timeout'));

        session()->put('timeout', now()->subSeconds(1));

        $this->json('POST', route('timeout-check'))
             ->assertStatus(419)
             ->assertJsonFragment([
                'error' => 'Session Expired',
             ]);
    }

    public function test_an_update_can_be_made_for_the_timeout_check()
    {
        $user = User::factory()->create([
            'password' => bcrypt('password'),
        ]);

        $this->json('POST', route('login'), [
            'email' => $user->email,
            'password' => 'password',
        ])
        ->assertSuccessful()
        ->assertSessionHas('timeout');

        $timeout = session()->get('timeout');

        sleep(2);

        $this->json('POST', route('timeout-check'))
             ->assertSuccessful()
             ->assertJsonFragment([
                'success' => 'Session Valid',
             ]);

        $this->assertEquals($timeout, session()->get('timeout'));

        $this->json('POST', route('timeout-check'), ['activity' => true])
             ->assertSuccessful()
             ->assertJsonFragment([
                'success' => 'Session Updated',
             ]);

        $this->assertGreaterThan($timeout, session()->get('timeout'));
    }

    public function test_trying_to_access_a_page_that_has_permissions_as_a_guest_asks_you_to_login_and_redirects()
    {
        $page = Page::factory()->create();
        $page->publish();
        $role = Role::factory()->create();
        $page->createPermission('view', $role);

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

        $this->get($page->full_slug)
             ->assertRedirect('/login');
        $this->assertNotNull(session()->get('url.intended'));
    }

    public function test_a_user_has_a_editing_token()
    {
        $user = User::factory()->create([
            'password' => bcrypt('password'),
            'activated_at' => null,
        ]);

        $this->json('POST', route('login'), ['email' => $user->email, 'password' => 'password'])
             ->assertJsonFragment([
                'redirect' => '/?success=Login%20Successful',
             ])
            ->assertSessionHas('timeout');

        $user->refresh();
        $this->assertNotNull(session()->has('editing-token'));
    }

    public function test_a_login_can_be_sent_to_a_previous_url()
    {
        $page = Page::factory()->create();
        $page->publish();

        $url = $page->full_slug;
        $this->assertNotNull($url);

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

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

        $this->json('POST', route('login'), ['email' => $user->email, 'password' => 'password'])
             ->assertJsonFragment([
                'redirect' => '/?success=Login%20Successful',
             ]);

        auth()->logout();

        $this->json('POST', route('login'), ['email' => $user->email, 'password' => 'password', 'previous_url' => $url])
             ->assertJsonFragment([
                 'redirect' => $url.'?success=Login%20Successful',
             ]);
    }

    public function test_logging_in_a_non_google_user_properly_redirects_from_the_intended_session_url()
    {
        $user = User::factory()->create([
            'password' => bcrypt('password'),
        ]);
        $page = Page::factory()->create();
        $page->publish();
        $page->refresh();

        $this->json('POST', route('intended-url'), ['url' => $page->full_slug])
             ->assertSuccessful()
            ->assertSessionHas('url.intended', $page->full_slug);

        $this->json('POST', route('login'), ['email' => $user->email, 'password' => 'password'])
             ->assertJsonFragment([
                'redirect' => $page->full_slug.'?success=Login%20Successful',
             ])
            ->assertSessionHas('timeout');
    }
}
