<?php

namespace Tests\Feature;

use App\User;
use App\Category;
use Tests\TestCase;
use App\ArticleDescription;
use Illuminate\Support\Facades\Session;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class ArticleTest extends TestCase
{
    // To reset DB to it's status before run test
    use DatabaseTransactions;

    // To create fake sentences to help us test and validation
    use WithFaker;

    private $user;


    protected function setUp() :void
    {
        parent::setUp();

        // to see description
        $this->withoutExceptionHandling();

        // Start session to enables csrf_token()
        Session::start();

        // Authenticate user
        $this->user = factory(User::class)->create(['role'=>'admin']);

        $this->actingAs($this->user);
    }

    /**
     * Method to ensure that the user can access to article.
     *
     * @return void
     */
    public function testUserCanAccessArticlePage() :void
    {
        // Article route which visit by user
        $response = $this->get(route('articles.index'));

        // Should be return status 200
        $response->assertStatus(200);
    }

    /**
     * Method to ensure that the user can read all articles.
     *
     * @return void
     */
    public function testUserCanReadAllArticles() :void
    {
        //Given we have article in the database
        $articleDescription = factory(ArticleDescription::class)->create();

        //When user visit the article
        $response = $this->get(route('articles.grid'));
        // status should be 200
        $response->assertStatus(200);

        //He should be able to read the article
        $response->assertSee($articleDescription->title);

    }

    /**
     * Method to ensure that the create form route exists.
     *
     * @return void
     */

    public function testUserCanCreateArticle()
    {
        //When user visit the new article form route
        $response = $this->get(route('articles.create'));

        $title = metaFields('articles', 'title', getCurrentLocale());

        //He should be able to see the fields which enable him to add new article
        $response->assertStatus(200);
        $response->assertSee($title ?? __('articles.title'));
    }

    /**
     * Method to ensure that the update form route exists.
     *
     * @return void
     */

    public function testUserCanEditArticle()
    {
        //Given we have article in the database
        $articleDescription = factory(ArticleDescription::class)->make();

        //When user visit the article form route
        $response = $this->get(route('articles.edit', $articleDescription->article_id));

        $title = metaFields('articles', 'title', getCurrentLocale());

        //He should be able to see the fields which enable him to edit the article
        $response->assertStatus(200);
        $response->assertSee($title ?? __('articles.title'));

        $response->assertSee($articleDescription['title_'.getCurrentLocale()]);
    }

    /**
     * Method to ensure that the user can add article and article description.
     *
     * @return void
     */
    public function testUserCanAddArticle() :void
    {
        $category = factory(Category::class)->create();

        $dataToSave = [
            'video_type' => 1,
            'category_id' => $category->id,
            'user_id' => $this->user->id,
        ];


        $video_url = 'https://www.youtube.com/watch?v=vfNI24pIEBY';
        $video = 'https://www.youtube.com/embed/vfNI24pIEBY';
        $image = 'https://img.youtube.com/vi/vfNI24pIEBY/hqdefault.jpg';
        $dataToSave['video_url'] = $video_url;
        if ($dataToSave['video_type'] == 1){
            $dataToSave['video_url'] = $video_url;
        } else {
            $dataToSave['image'] = '/uploads/images/5eafffbad512e.jpg';
            $dataToSave['video'] = '/uploads/images/5eafffbad512e.mp4';
        }

        $dataToSave['images'] = [
            '/uploads/images/5eafffbad512e.jpg',
            '/uploads/images/5eafffbad512e.jpg',
            '/uploads/images/5eafffbad512e.jpg',
        ];


        foreach (languages() as $key => $language) {
            $dataToSave['title_'.$language->local] = $this->faker->sentence;
            $dataToSave['description_'.$language->local] = $this->faker->sentence;
            $dataToSave['slug_'.$language->local] = $this->faker->unique()->sentence;
            $dataToSave['meta_description_'.$language->local] = $this->faker->sentence;
            $dataToSave['keywords_'.$language->local] = $this->faker->sentence;
        }


        //When user submits post request to create article endpoint
        $response= $this->post(route('articles.store'), array_merge( $dataToSave, ['_token'=> csrf_token()]));

        // The redirect response header status is 302
        $response->assertStatus(302);

        // The response redirect to articles
        $response->assertRedirect('admin/articles');

        //It gets stored in the database
        $this->assertDatabaseHas('articles',
            [
                'image'=> $dataToSave['video_type'] == 1 ? $image : $dataToSave['image'],
                'video'=> $dataToSave['video_type'] == 1 ? $video : $dataToSave['video'],
                'category_id'=> $dataToSave['category_id'],
                'user_id'=>  $this->user->id,
            ]
        );

        foreach ($dataToSave['images'] as $image) {
            $this->assertDatabaseHas('article_photos', ['image' => $image,]);
        }


        foreach (languages() as $key => $language) {
            $this->assertDatabaseHas('article_descriptions',
                [
                    'title' => $dataToSave['title_' . $language->local],
                    'description' => $dataToSave['description_' . $language->local],
                    'slug' => $dataToSave['slug_' . $language->local],
                    'meta_description' => $dataToSave['meta_description_' . $language->local],
                    'keywords' => $dataToSave['keywords_' . $language->local],
                ]
            );
        }


        // Session success message
        $response->assertSessionHas('message', __('dashboard.saveDone'));

        // Page appears in the Pages panel
        $response = $this->get(route('articles.grid'));

        //He should be able to read the article
        $response->assertSee($dataToSave['title_'.getCurrentLocale()]);

    }

    /**
     * Method to ensure that the user can Edit article.
     *
     * @return void
     */
    public function testUserCanUpdateArticle() :void
    {

        //Add a article object
        $articleDescription = factory(ArticleDescription::class)->create();

        $dataToSave = [
            'video_type' => rand(1,2),
            'category_id' => $articleDescription->article->category_id,
            'user_id' => $this->user->id,
        ];


        $video_url = 'https://www.youtube.com/watch?v=vfNI24pIEBY';
        $video = 'https://www.youtube.com/embed/vfNI24pIEBY';
        $image = 'https://img.youtube.com/vi/vfNI24pIEBY/hqdefault.jpg';

        if ($dataToSave['video_type'] == 1){
            $dataToSave['video_url'] = $video_url;
        } else {
            $dataToSave['image'] = '/uploads/images/5eafffbad512e.jpg';
            $dataToSave['video'] = '/uploads/images/5eafffbad512e.mp4';
        }

        $dataToSave['images'] = [
            '/uploads/images/5eafffbad512e.jpg',
            '/uploads/images/5eafffbad512e.jpg',
            '/uploads/images/5eafffbad512e.jpg',
        ];

        foreach (languages() as $key => $language) {
            $dataToSave['title_'.$language->local] = $this->faker->sentence;
            $dataToSave['description_'.$language->local] = $this->faker->sentence;
            $dataToSave['slug_'.$language->local] = $this->faker->unique()->sentence;
            $dataToSave['meta_description_'.$language->local] = $this->faker->sentence;
            $dataToSave['keywords_'.$language->local] = $this->faker->sentence;
        }



        //When user submits post request to edit article endpoint
        $response= $this->put(route('articles.update', $articleDescription->article_id),array_merge( $dataToSave, ['_token'=> csrf_token(), 'article' => null] ) );

        // The redirect response header status is 302
        $response->assertStatus(302);

        // The response redirect to articles
        $response->assertRedirect('/admin/articles');


        //It gets stored in the database
        $this->assertDatabaseHas('articles',
            [
                'image'=> $dataToSave['video_type'] == 1 ? $image : $dataToSave['image'],
                'video'=> $dataToSave['video_type'] == 1 ? $video : $dataToSave['video'],
                'category_id'=> $dataToSave['category_id'],
                'user_id'=>  $this->user->id,
            ]
        );

        foreach ($dataToSave['images'] as $image) {
            $this->assertDatabaseHas('article_photos', ['image' => $image,]);
        }


        foreach (languages() as $key => $language) {
            $this->assertDatabaseHas('article_descriptions',
                [
                    'title' => $dataToSave['title_' . $language->local],
                    'description' => $dataToSave['description_' . $language->local],
                    'slug' => $dataToSave['slug_' . $language->local],
                    'meta_description' => $dataToSave['meta_description_' . $language->local],
                    'keywords' => $dataToSave['keywords_' . $language->local],
                ]
            );
        }


        // Session success message
        $response->assertSessionHas('message', __('dashboard.saveDone'));

        // Page appears in the Page grid
        $response = $this->get(route('articles.grid'));

        //He should be able to read the article
        $response->assertSee($dataToSave['title_'.getCurrentLocale()]);

    }

    /**
     * Method to ensure that the user can send the article to trash.
     *
     * @return void
     */
    public function testArticlesTrash() :void
    {

        //Add a article object
        $articleDescription = factory(ArticleDescription::class)->make();

        //When the user hit's with endpoint to delete the article
        $this->delete(route('articles.destroy', $articleDescription->article_id), ['_token'=> csrf_token()]);

        //The article should be deleted from the database.
        $this->assertSoftDeleted('articles',['id'=> $articleDescription->article_id]);
    }

    /**
     * Method to ensure that the user can delete the article from database.
     *
     * @return void
     */
    public function testArticlesDelete() :void
    {
        //Add a article object
        $articleDescription = factory(ArticleDescription::class)->make();

        // user sent the article to trash first, as he can not delete it from the first click
        $this->delete(route('articles.destroy', $articleDescription->article_id), ['_token'=> csrf_token()]);

        //When the user hit's the endpoint to delete the article
        $this->delete(route('articles.destroy', $articleDescription->article_id), ['_token'=> csrf_token()]);

        //The article should be deleted from the database.

        $this->assertDatabaseMissing('articles',['id'=> $articleDescription->article_id]);

        $this->assertDatabaseMissing('article_descriptions',['article_id'=> $articleDescription->article_id]);
    }

    /**
     * Method to ensure that the user can send multiple articles to trash.
     *
     * @return void
     */
    public function testArticlesMultiTrash() :void
    {
        //Add a article object
        $articleDescription = factory(ArticleDescription::class, 3)->make();

        $ids= $articleDescription->pluck('article_id')->toArray();

        //When the user hit's the endpoint to send the article to trash
        $this->delete(route('articles.destroyAll'), ['_token'=> csrf_token(), 'ids'=> $ids]);
        //The article should be deleted from the database.
        $this->assertSoftDeleted('articles',['id'=> $ids]);
    }

    /**
     * Method to ensure that the user can delete multiple article categories.
     *
     * @return void
     */
    public function testArticlesMultiDelete() :void
    {
        //Add a article object
        $articleDescription = factory(ArticleDescription::class, 3)->make();

        $ids= $articleDescription->pluck('article_id')->toArray();

        //When the user hit's the endpoint to send the articles to trash
        $this->delete(route('articles.destroyAll'), ['_token'=> csrf_token(), 'ids'=> $ids]);

        //When the user hit's the endpoint to delete the articles from the db
        $this->delete(route('articles.destroyAll'), ['_token'=> csrf_token(), 'ids'=> $ids, 'force' => true]);

        //The article should be deleted from the database.
        $this->assertDatabaseMissing('articles',['id'=> $ids]);

        $this->assertDatabaseMissing('article_descriptions',['article_id'=> $ids]);

    }

    /**
     * Method to ensure that the user can restore the article from trash.
     *
     * @return void
     */
    public function testArticlesRestore() :void
    {
        //Add a article object
        $articleDescription = factory(ArticleDescription::class)->make();

        //the user send the article to trash
        $this->delete(route('articles.destroy', $articleDescription->article_id), ['_token'=> csrf_token()]);

        $this->assertSoftDeleted('articles',['id'=> $articleDescription->article_id]);

        //the user restore the article
        $this->put(route('articles.restore', $articleDescription->article_id), ['_token'=> csrf_token()]);

        //The article should be restored .
        $this->assertDatabaseHas('articles',['id'=> $articleDescription->article_id, 'deleted_at'=> null]);
    }

    /**
     * Method to ensure that the user can restore multiple articles.
     *
     * @return void
     */
    public function testArticlesMultiRestore() :void
    {
        //Add a article object
        $articleDescription = factory(ArticleDescription::class, 3)->make();

        $ids= $articleDescription->pluck('article_id')->toArray();

        //When the user hit's the endpoint to send the article to trash
        $response = $this->delete(route('articles.destroyAll'), ['_token' => csrf_token(), 'ids' => $ids]);

        // Test last one to ensure soft deleted process done successfully
        $this->assertSoftDeleted('articles', ['id' => $ids]);

        //When the user hit's the endpoint to restore the articles from the trash
        $this->put(route('articles.restoreAll'), ['_token' => csrf_token(), 'ids' => $ids]);

        // Test last one to ensure restore process done successfully
        $this->assertDatabaseHas('articles', ['id' => $ids, 'deleted_at' => null]);

    }
}
