<?php

namespace Tests\Feature;

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

use App\Models\PageSlug;
use App\Models\Page;
use App\Models\TextBlock;
use App\Models\PhotoBlock;
use App\Models\User;
use Illuminate\Support\Str;

class PageSlugTest extends TestCase
{
    public function test_a_page_can_have_many_slugs()
    {
        $super_parent = Page::factory()->create();
        $parent = Page::factory()->create();
        $version = $parent->versions->first();
        $version->parent_page_id = $super_parent->id;
        $version->save();

        $page = Page::factory()->create();
        $content_element = $this->createContentElement(TextBlock::factory(), $page);
        $version = $page->versions->first();
        $version->parent_page_id = $parent->id;
        $version->save();

        $super_parent->publish();
        $parent->publish();
        $page->publish();

        $slug = Str::random();

        $page_slug = PageSlug::factory()->create([
            'pageable_id' => $page->id,
            'pageable_type' => get_class($page),
            'slug' => $slug,
        ]);

        $this->assertTrue($page->pageSlugs()->get()->contains('slug', $slug));

        $this->assertEquals($page_slug->pageable->id, $page->id);
        $this->assertEquals(get_class($page_slug->pageable), get_class($page));

        $this->assertNotNull($page->parent_slug);
        $this->assertEquals($parent->full_slug, $page->parent_slug);

        $url = $page->parent_slug.'/'.$page_slug->slug;

        $this->assertNotNull($content_element->content->header);

        $this->withoutExceptionHandling();
        $this->get($url)
            ->assertSuccessful()
            ->assertSee($content_element->content->header);
    }

    public function test_a_page_slug_doesnt_need_a_parent()
    {
        $page = Page::factory()->create();
        $content_element = $this->createContentElement(TextBlock::factory(), $page);
        $page->publish();

        $slug = Str::random();

        $page_slug = PageSlug::factory()->create([
            'pageable_id' => $page->id,
            'pageable_type' => get_class($page),
            'slug' => $slug,
        ]);

        $this->assertNotNull($content_element->content->header);

        $this->withoutExceptionHandling();
        $this->get($slug)
            ->assertSuccessful()
            ->assertSee($content_element->content->header);
    }

    public function test_a_page_slug_can_be_created()
    {
        $page = Page::factory()->create();
        $page->publish();
        $slug = Str::random();

        $this->assertNotNull($page->full_type);

        $input = [
            'slug' => $slug,
            'pageable_id' => $page->id,
            'pageable_type' => $page->full_type,
            'root' => false,
        ];

        $this->json('POST', route('page-slugs.store'))
            ->assertStatus(401);

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

        $this->json('POST', route('page-slugs.store'), $input)
            ->assertStatus(403);

        $this->signInAdmin();
        $this->enableEditing();

        $this->json('POST', route('page-slugs.store'), [])
            ->assertStatus(422)
            ->assertJsonValidationErrors([
                'slug',
                'pageable_id',
                'pageable_type',
            ]);

        $this->withoutExceptionHandling();
        $this->json('POST', route('page-slugs.store'), $input)
             ->assertSuccessful()
             ->assertJsonFragment([
                'success' => 'Alias Saved',
             ]);

        $page_slug = PageSlug::all()->last();
        $this->assertEquals(Arr::get($input, 'slug'), $page_slug->slug);
        $this->assertEquals($page->id, $page_slug->pageable->id);
        $this->assertEquals(get_class($page), get_class($page_slug->pageable));

        $this->get($slug)
            ->assertSuccessful();
    }

    public function test_a_page_slug_can_be_removed()
    {
        $page_slug = PageSlug::factory()->create();
        $pageable = $page_slug->pageable;
        $slug = $page_slug->slug;

        $this->json('POST', route('page-slugs.remove', ['id' => $page_slug->id]))
            ->assertStatus(401);

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

        $this->json('POST', route('page-slugs.remove', ['id' => $page_slug->id]))
            ->assertStatus(403);

        $this->signInAdmin();
        $this->enableEditing();

        $this->json('POST', route('page-slugs.remove', ['id' => $page_slug->id]))
             ->assertSuccessful()
            ->assertJsonFragment([
                'success' => 'Alias Removed',
            ]);

        $this->assertNull(PageSlug::where('slug', $slug)->first());
    }

    public function test_a_page_slug_can_be_from_the_root()
    {
        $super_parent = Page::factory()->create();
        $parent = Page::factory()->create();
        $version = $parent->versions->first();
        $version->parent_page_id = $super_parent->id;
        $version->save();

        $page = Page::factory()->create();
        $content_element = $this->createContentElement(TextBlock::factory(), $page);

        $header = $content_element->content->header;
        $this->assertNotNull($header);

        $version = $page->versions->first();
        $version->parent_page_id = $parent->id;
        $version->save();

        $super_parent->publish();
        $parent->publish();
        $page->publish();

        $slug = Str::random();

        $this->assertNotNull($page->full_type);

        $input = [
            'slug' => $slug,
            'pageable_id' => $page->id,
            'pageable_type' => $page->full_type,
            'root' => true,
        ];

        $this->signInAdmin();
        $this->enableEditing();

        $this->json('POST', route('page-slugs.store'), [])
            ->assertStatus(422)
            ->assertJsonValidationErrors([
                'slug',
                'pageable_id',
                'pageable_type',
                'root',
            ]);

        $this->withoutExceptionHandling();
        $this->json('POST', route('page-slugs.store'), $input)
             ->assertSuccessful()
             ->assertJsonFragment([
                'success' => 'Alias Saved',
             ]);

        $page_slug = PageSlug::all()->last();
        $this->assertEquals(Arr::get($input, 'slug'), $page_slug->slug);
        $this->assertEquals($page->id, $page_slug->pageable->id);
        $this->assertEquals(get_class($page), get_class($page_slug->pageable));
        $this->assertTrue($page_slug->root);

        $this->disableEditing();

        $this->get('/'.$slug)
             ->assertSuccessful()
             ->assertSee($header);
    }

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

        $this->json('POST', route('page-slugs.get-slug'), [])
             ->assertStatus(401);

        $this->signInAdmin();
        $this->enableEditing();

        $this->json('POST', route('page-slugs.get-slug'), [])
             ->assertStatus(422)
             ->assertJsonValidationErrors([
                'item_id',
                'item_type',
             ]);

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

        $input = [
            'item_id' => $page->id,
            'item_type' => 'page',
        ];

        $this->withoutExceptionHandling();
        $this->json('POST', route('page-slugs.get-slug'), $input)
             ->assertSuccessful()
             ->assertJsonFragment([
                'slug' => $page->full_slug,
             ]);
    }

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

        $this->signInAdmin();
        $this->enableEditing();

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

        $input = [
            'item_slug' => $page->full_slug,
            'item_type' => 'page',
        ];

        $this->json('POST', route('page-slugs.get-link'), $input)
             ->assertSuccessful()
             ->assertJsonFragment([
                'link' => $page->id,
             ]);

        $input['item_slug'] = 'https://www.google.com';

        $this->json('POST', route('page-slugs.get-link'), $input)
             ->assertSuccessful()
             ->assertJsonFragment([
                 'link' => null,
             ]);
    }

    public function test_a_slug_can_be_generated_for_a_page_and_hash()
    {
        $page = Page::factory()->create();
        $content_element = $this->createContentElement(PhotoBlock::factory()->withText(), $page);

        $this->signInAdmin();
        $this->enableEditing();

        $this->assertNotNull($page->full_slug);
        $this->assertNotNull($content_element->content->header);
        $this->assertNotNull($content_element->anchor);

        $input = [
            'item_id' => $page->id.'#c-'.$content_element->uuid,
            'item_type' => 'page',
        ];

        $this->withoutExceptionHandling();
        $this->json('POST', route('page-slugs.get-slug'), $input)
             ->assertSuccessful()
             ->assertJsonFragment([
                'slug' => $page->full_slug.'#'.$content_element->anchor,
             ]);
    }
}
