<?php

namespace Tests\Browser;

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\WithFaker;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

use Tests\Browser\Components\Feedback;
use Tests\Browser\Components\Editor;
use Tests\Browser\Components\Autocomplete;
use Tests\Browser\Components\PhotoUpload;
use Tests\Browser\Components\AddContentElement;
use Tests\Browser\Pages\Login;
use Tests\Browser\Scroll;

use App\Models\User;
use App\Models\Blog;
use App\Models\Announcement;
use App\Models\Page;
use App\Models\ContentElement;
use App\Models\Tag;
use App\Models\PhotoBlock;
use App\Models\PublicationLayout;

trait PublicationsTestTrait
{
    use WithFaker;

    abstract protected function getModel();
    abstract protected function getClassname();

    public function test_a_publication_can_be_created_published_and_viewed()
    {
        $this->browse(function ($browser) {
            $user = User::factory()->create();

            $browser->visit(new Login())
                ->loginUser($user)
                ->assertAuthenticatedAs($user)
                ->visitRoute(Str::plural($this->getClassname()).'.manage')
                ->assertPathIsNot('/'.Str::plural($this->getClassname()).'-manage');

            $user->addRole(Str::plural($this->getClassname()).'-manager');
            $user->refresh();

            $publication_name = Str::random(20);

            $browser->visitRoute(Str::plural($this->getClassname()).'.manage')
                ->waitForRoute(Str::plural($this->getClassname()).'.manage')
                ->waitFor('@'.Str::plural($this->getClassname()).'-paginator')
                ->pause(500)
                ->click('@show-create-'.$this->getClassname())
                ->with('@modal', function ($browser) use ($publication_name) {
                    $browser->waitFor('@form-new-'.$this->getClassname())
                        ->pause(500)
                        ->type('@name', $publication_name)
                        ->click('@create-'.$this->getClassname());
                })
                ->within(new Feedback(), function ($browser) use ($publication_name) {
                    $browser->assertFeedbackContains('You do not have permission to create that page');
                });

            $user->addRole(Str::plural($this->getClassname()).'-editor');
            $user->refresh();
            $class = 'App\Models\\'.Str::title($this->getClassname());
            $this->assertTrue($user->can('create', $class));

            $browser->refresh()
                ->waitFor('@show-create-'.$this->getClassname())
                ->pause(500)
                ->click('@show-create-'.$this->getClassname())
                ->pause(500)
                ->with('@modal', function ($browser) use ($publication_name) {
                    $browser->waitFor('@form-new-'.$this->getClassname())
                        ->pause(500)
                        ->type('@name', $publication_name)
                        ->click('@create-'.$this->getClassname());
                })
                ->within(new Feedback(), function ($browser) use ($publication_name) {
                    $browser->assertFeedbackContains($publication_name.' Saved');
                });

            $publication = $class::all()->last();
            $slug = $this->getEditingValue($publication, 'full_slug');
            $this->assertEquals($publication_name, $this->getEditingValue($publication, 'name'));

            $tag = Tag::factory()->create();

            $browser->waitForLocation('/'.$slug)
                ->pause(500)
                ->waitFor('@editing-button')
                ->assertVue('editing', true, '@editing-button')
                ->assertMissing('@page-side-menu')
                ->waitFor('@page-editor')
                ->with('@page-editor', function ($browser) use ($publication_name, $tag) {
                    $browser->assertValue('@page-version-name', $publication_name)
                        ->with(new Autocomplete('tags'), function ($browser) use ($tag) {
                            $browser->searchAndSelectMultiple($tag);
                        });
                });

            $browser->with(new AddContentElement(), function ($browser) {
                $browser->create('photo-block');
            })
            ->pause(1500);

            $content_element1 = ContentElement::all()->last();

            Scroll::centerInView($browser, '@content-element-'.$content_element1->id);

            $browser->with(new PhotoUpload($content_element1), function ($browser) {
                $browser->addPhoto();
            })->pause(1500);

            $browser->with(new AddContentElement(), function ($browser) {
                $browser->create('photo-block');
            })
            ->pause(1500);

            $content_element2 = ContentElement::all()->last();
            $input = PhotoBlock::factory()->withText()->raw();

            $browser->with('@content-element-'.$content_element2->id, function ($browser) use ($content_element2, $input) {
                $browser->waitFor('@toggle-text')
                        ->click('@toggle-text')
                        ->waitFor('@header')
                        ->pause(500)
                        ->type('@header', Arr::get($input, 'header'))
                        ->within(new Editor('body', $content_element2->id), function ($browser) use ($input) {
                            $browser->typeInEditor(Arr::get($input, 'body'));
                        });
            })
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Photo Block Saved');
                })
                ->pause(1500)
                ->assertVisible('@link-'.$this->getClassname().'-listings')
                ->visit(route(Str::plural($this->getClassname()).'.manage'))
                ->waitForRoute(Str::plural($this->getClassname()).'.manage')
                ->waitFor('@'.Str::plural($this->getClassname()).'-paginator')
                ->with('@'.Str::plural($this->getClassname()).'-paginator', function ($browser) use ($publication_name, $publication) {
                    $browser->type('@paginator-search', $publication_name)
                            ->waitFor('@'.$this->getClassname().'-'.$publication->id, 10)
                            ->click('@'.$this->getClassname().'-name');
                })
                ->waitForLocation('/'.$slug)
                ->waitFor('@page-editor')
                ->with('@page-editor', function ($browser) {
                    $browser->assertMissing('@publish-page')
                            ->assertVisible('@request-publishing')
                            ->click('@request-publishing');
                })
                ->acceptDialog()
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Publishing Requested');
                });

            $page = Page::factory()->create();
            $user->createPermission('update', $page);
            $user->createPermission('publish', $page);
            //$user->addRole('blogs-editor');
            $user->addRole('pages-editor');
            $user->refresh();
            $page_slug = $this->getEditingValue($page, 'full_slug');

            $browser->visit('/'.$page_slug)
                ->waitForLocation('/'.$page_slug)
                ->waitFor('@editing-button')
                ->assertVue('editing', true, '@editing-button')
                ->waitFor('@page-editor')
                ->assertVue('page.id', $page->id, '@page-editor')
                ->with(new AddContentElement(), function ($browser) {
                    $browser->create('publication-list');
                })
                ->pause(1500);

            $content_element3 = ContentElement::all()->last();
            $header = $this->faker->words(3, true);

            $browser->with('@content-element-'.$content_element3->id, function ($browser) use ($tag, $header) {
                $browser->waitFor('@header')
                    ->type('@header', $header)
                    ->with('@select-buttons-publication-list-type', function ($browser) {
                        $browser->click('@select-'.$this->getClassname());
                    })
                    ->with(new Autocomplete('tags'), function ($browser) use ($tag) {
                        $browser->searchAndSelectMultiple($tag);
                    })
                    ->click('@add-thumbnail');
            })
                ->pause(1500)
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Publication List Saved');
                });

            $publication_layout = PublicationLayout::all()->last();

            $browser->with('@content-element-'.$content_element3->id, function ($browser) use ($publication_layout, $publication_name, $tag, $publication) {
                $browser->waitFor('@publication-layout-'.$publication_layout->id)
                        ->waitFor('@publication-thumbnail-'.$publication->id)
                        ->with('@publication-thumbnail-'.$publication->id, function ($browser) use ($publication_name, $tag) {
                            $browser->assertSee($publication_name);
                            //->assertSee($tag->name);
                        });
            })
                ->click('@publish-page')
                ->acceptDialog()
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Page Published');
                });

            $user->addRole(Str::plural($this->getClassname()).'-publisher');
            $user->refresh();
            $this->assertTrue($user->can('publish', $publication));

            $browser->visit('/'.$slug)
                ->waitFor('@page-editor')
                ->waitFor('@publish-page')
                ->click('@publish-page')
                ->acceptDialog()
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains(Str::title($this->getClassname()).' Published');
                })
                ->pause(1000)
                ->waitForReload(function ($browser) {
                    $browser->click('@editing-button');
                })
                ->waitFor('@editing-button')
                ->assertVue('editing', false, '@editing-button')
                ->visit('/'.$page_slug)
                ->waitFor('@publication-thumbnail-'.$publication->id)
                ->click('@publication-thumbnail-'.$publication->id)
                ->waitForLocation('/'.$slug)
                ->waitFor('@content-element-'.$content_element1->id)
                ->waitFor('@content-element-'.$content_element2->id)
                ->assertSee(Arr::get($input, 'header'))
                ->assertSee(Arr::get($input, 'body'))

                ->visitRoute(Str::plural($this->getClassname()).'.manage')
                ->waitForRoute(Str::plural($this->getClassname()).'.manage')
                ->waitFor('@'.Str::plural($this->getClassname()).'-paginator')
                ->with('@'.Str::plural($this->getClassname()).'-paginator', function ($browser) use ($publication, $publication_name) {
                    $browser->type('@paginator-search', $publication_name)
                        ->pause(1000)
                        ->waitFor('@'.$this->getClassname().'-'.$publication->id, 10)
                        ->with('@'.$this->getClassname().'-'.$publication->id, function ($browser) use ($publication) {
                            $browser->assertDontSee('DRAFT')
                                ->assertSee($publication->published_at->setTimezone('America/Vancouver')->format('M j, \'y g:ia'));
                        });
                });
        });
    }
}
