<?php

namespace Tests\Browser;

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

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

use App\Models\Page;
use App\Models\ContentElement;
use App\Models\Photo;
use App\Models\PhotoBlock;
use App\Models\User;

class PhotoBlockTest extends DuskTestCase
{
    use WithFaker;

    public function test_a_photo_block_can_be_saved()
    {
        $this->browse(function (Browser $browser) {
            $page = Page::factory()->create();
            $user = User::factory()->create();
            $user->createPermission('publish', $page);

            $page2 = Page::factory()->create();
            $user->createPermission('update', $page2);
            $user->createPermission('publish', $page2);

            cache()->tags(['photos'])->flush();

            auth()->login($user);
            $user->addRole('web-committee');
            $user->refresh();
            $this->assertTrue(Photo::getPhotos()->count() > 2);

            $existing_photos = Photo::getPhotos()->take(3);
            $existing_photo = $existing_photos[0];
            $this->assertNotNull($existing_photo);
            $this->assertInstanceOf(Photo::class, $existing_photo);
            auth()->logout();

            cache()->tags(['photos'])->flush();

            $browser->visit(new Login())
                ->loginAndEditPage($page, $user)
                ->waitFor('@content-elements-editor')
                ->with(new AddContentElement(), function ($browser) {
                    $browser->create('photo-block');
                });

            $content_element = ContentElement::all()->last();
            $header = $this->faker->sentence(3);
            $body = $this->faker->paragraph();

            $browser->with('@content-element-'.$content_element->id, function ($browser) use ($header, $body, $content_element) {
                $browser->waitFor('@toggle-text')
                        ->click('@toggle-text')
                        ->pause(1500)
                        ->waitFor('@header')
                        ->type('@header', $header)
                        ->within(new Editor('body', $content_element->id), function ($browser) use ($body) {
                            $browser->typeInEditor($body);
                        });
            })
            ->pause(1300) // so that the debounce triggers
            ->within(new Feedback(), function ($browser) {
                $browser->assertFeedbackContains('Photo Block Saved');
            });

            $content_element->refresh();

            $this->assertEquals($header, $content_element->content->header);
            $this->assertEquals('<p>'.$body.'</p>', $content_element->content->body);

            $browser->with(new PhotoUpload($content_element), function ($browser) {
                $browser->addPhoto();
            });

            $photo = Photo::all()->last();
            $caption = $this->faker->sentence();
            $alt = $this->faker->sentence();
            $span = $photo->span;

            $browser->whenAvailable('@form-photo-'.$photo->id, function ($browser) use ($photo, $alt, $caption) {
                $browser->assertSourceHas($photo->large)
                    ->type('@caption', $caption)
                    ->type('@alt', $alt)
                    ->click('@increase-width');
            })->pause(1500);

            $photo->refresh();
            $this->assertEquals($span + 1, $photo->span);
            $this->assertEquals($alt, $photo->alt);
            $this->assertEquals($caption, $photo->description);

            $hide_mobile = $photo->hide_mobile;
            $hide_print = $photo->hide_print;
            $enlarge = $photo->enlarge;

            $browser->with('@form-photo-'.$photo->id, function ($browser) use ($photo) {
                $browser->click('@all-buttons')
                    ->click('@hide-mobile')
                    ->click('@hide-print')
                    ->click('@enlarge')
                    ->click('@decrease-width');
            })->pause(1500);

            $photo->refresh();
            $this->assertEquals($span, $photo->span);
            $this->assertEquals(!$hide_mobile, $photo->hide_mobile);
            $this->assertEquals(!$hide_print, $photo->hide_print);
            $this->assertEquals(!$enlarge, $photo->enlarge);

            $subtitle = $this->faker->sentence(2);
            $title = $this->faker->randomNumber();

            $browser->with('@form-photo-'.$photo->id, function ($browser) use ($subtitle, $title) {
                $browser->click('@all-buttons')
                    ->click('@show-titles')
                    ->waitFor('@subtitle')
                    ->type('@subtitle', $subtitle)
                    ->type('@title', $title);
            })->pause(1500);

            $photo->refresh();
            $this->assertEquals($subtitle, $photo->subtitle);
            $this->assertEquals($title, $photo->title);

            $browser->with(new PhotoUpload($content_element), function ($browser) use ($existing_photo) {
                $browser->addPhoto($existing_photo);
            });

            $browser->assertDontSee('@file-uploads-form');

            $content_element->refresh();
            $this->assertEquals(2, $content_element->content->photos()->count());

            $existing_photo2 = $existing_photos[1];
            $this->assertNotNull($existing_photo2);

            $browser->with('@content-element-'.$content_element->id, function ($browser) use ($photo) {
                $browser->waitFor('@replace-photo-'.$photo->id)
                    ->click('@replace-photo-'.$photo->id);
            })
            ->with('@modal', function ($browser) use ($existing_photo2) {
                $browser->waitFor('@photo-container-'.$existing_photo2->id, 30)
                        ->click('@photo-'.$existing_photo2->id)
                        ->click('@add-images');
            })
            ->click('@debug')
            ->pause(1500)
            ->within(new Feedback(), function ($browser) {
                $browser->assertFeedbackContains('Photo Replaced')
                    ->assertFeedbackContains('Photo Block Saved');
            });

            $photo = Photo::all()->last();

            $this->assertNotNull($photo->subtitle);
            $this->assertNotNull($photo->title);

            $browser->with('@form-photo-'.$photo->id, function ($browser) use ($photo) {
                $browser->waitFor('@link-photo')
                    ->click('@link-photo');
            });

            $browser->with('@modal', function ($browser) use ($page2) {
                $browser->with('@link-menu', function ($browser) use ($page2) {
                    $browser->waitFor('@page-list-'.$page2->id)
                            ->click('@page-list-'.$page2->id);
                });
            })
                ->pause(1500)
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Photo Block Saved');
                })

                ->click('@publish-page')
                ->acceptDialog()
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Page Published');
                })

                ->within(new PageSideMenu(), function ($browser) use ($page2) {
                    $browser->loadPage($page2);
                })

                ->waitFor('@page-editor')
                ->click('@publish-page')
                ->acceptDialog()
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Page Published');
                })

                ->within(new PageSideMenu(), function ($browser) use ($page) {
                    $browser->loadPage($page);
                })

                ->clickAndWaitForReload('@editing-button')
                ->assertNotPresent('@page-editor')
                ->click('@photo-'.$photo->id);

            $page2->refresh();

            $browser->waitForLocation('/'.$page2->full_slug);
        });
    }

    public function test_linking_a_photo_to_a_page_and_content_and_removing_the_link()
    {
        $this->browse(function (Browser $browser) {
            $page = Page::factory()->create();
            $user = User::factory()->create();
            $user->createPermission('publish', $page);

            $page2 = Page::factory()->create();
            $user->createPermission('update', $page2);
            $user->createPermission('publish', $page2);

            $browser->visit(new Login())
                ->loginAndEditPage($page, $user)
                ->waitFor('@content-elements-editor')
                ->with(new AddContentElement(), function ($browser) {
                    $browser->create('photo-block');
                });

            $content_element = ContentElement::all()->last();
            $content_element2 = $this->createContentElement(PhotoBlock::factory()->withText(), $page2);
            $header = $content_element2->content->header;
            $this->assertNotNull($header);

            $browser->with(new PhotoUpload($content_element), function ($browser) {
                $browser->addPhoto();
            });

            $photo = Photo::all()->last();

            $browser->with('@form-photo-'.$photo->id, function ($browser) {
                $browser->waitFor('@link-photo')
                    ->click('@link-photo');
            });

            $browser->with('@modal', function ($browser) use ($page2) {
                $browser->with('@link-menu', function ($browser) use ($page2) {
                    $browser->waitFor('@page-list-'.$page2->id)
                            ->click('@page-list-'.$page2->id)
                            ->pause(500);
                });
            })
                ->with('@form-photo-'.$photo->id, function ($browser) use ($page2) {
                    $browser->assertInputValue('@title', $this->getEditingValue($page2, 'name'));
                })
                ->pause(1500)
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Photo Block Saved');
                });

            $photo->refresh();
            $this->assertNotNull($photo->link);
            $link = $this->getEditingValue($photo, 'link');
            $this->assertEquals($page2->id, $link);

            $browser->with('@form-photo-'.$photo->id, function ($browser) {
                $browser->waitFor('@link-photo')
                    ->click('@link-photo');
            })
            ->with('@modal', function ($browser) use ($page2, $content_element2) {
                $browser->with('@link-menu', function ($browser) use ($page2, $content_element2) {
                    $browser->waitFor('@page-list-'.$page2->id)
                            ->click('@page-list-'.$page2->id.'-toggle-content-elements')
                            ->pause(500)
                            ->waitFor('@content-element-'.$content_element2->id)
                            ->click('@content-element-'.$content_element2->id)
                            ->pause(500);
                });
            })
                ->with('@form-photo-'.$photo->id, function ($browser) use ($header) {
                    $browser->assertInputValue('@title', $header);
                })
                ->pause(1500)
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Photo Block Saved');
                });

            $photo->refresh();
            $this->assertNotNull($photo->link);
            $link = $this->getEditingValue($photo, 'link');
            $this->assertEquals($page2->id.'#c-'.$content_element2->uuid, $link);

            $browser->with('@form-photo-'.$photo->id, function ($browser) use ($photo) {
                $browser->click('@link-photo');
            })
                ->with('@modal', function ($browser) {
                    $browser->waitFor('@remove-link')
                        ->click('@remove-link');
                })
                ->pause(1500)
                ->within(new Feedback(), function ($browser) {
                    $browser->assertFeedbackContains('Photo Block Saved');
                });

            $photo->refresh();
            $this->assertNull($photo->link);
        });
    }
}
