<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Support\Facades\Session;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class CategoryTest extends TestCase
{
    // To reset DB to its old status before perform Module Test data
    use DatabaseTransactions;

    // To create sentence to help us test Update and validation
    use WithFaker;

    private $user;

    /**
     * Method to setUp test requirements, like start session.
     *
     * @return void
     */
    protected function setUp(): void
    {
        parent::setUp();

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

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

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

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

    /**
     * Method to ensure that the user can read all categories.
     *
     * @return void
     */

    public function testUserCanAccessCategoriesPanel()
    {
        //When user visit the categories page
        $response = $this->get('/admin/categories');

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

    /**
     * Method to ensure that the user can read all categories.
     *
     * @return void
     */

    public function testUserCanReadAllCategories()
    {
        //Given we have category in the database
        $category = factory('App\CategoryDescription')->create();

        //When user visit the categories page
        $response = $this->get('/admin/categories/grid');

        // status should be 200
        $response->assertStatus(200);

        //He should be able to read the category
        $response->assertSee($category->name);
    }

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

    public function testUserCanCreateCategory()
    {
        //When user visit the new category form route
        $response = $this->get('/admin/categories/create');

        $name = metaFields('categories', 'name', getCurrentLocale());
        $slug = metaFields('categories', 'slug', getCurrentLocale());
        $keywords = metaFields('categories', 'keywords', getCurrentLocale());
        $meta_description = metaFields('categories', 'meta_description', getCurrentLocale());

        //He should be able to see the fields which enable him to add new category
        $response->assertStatus(200);
        $response->assertSee($name ?? __('categories.name'));
        $response->assertSee($slug ?? __('categories.slug'));
        $response->assertSee($keywords ?? __('categories.keywords'));
        $response->assertSee($meta_description ?? __('categories.meta_description'));
    }

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

    public function testUserCanEditCategory()
    {
        //Given we have category in the database
        $category = factory('App\CategoryDescription')->create();

        //When user visit the categories form route
        $response = $this->get("/admin/categories/{$category->category_id}/edit");

        $name = metaFields('categories', 'name', getCurrentLocale());
        $slug = metaFields('categories', 'slug', getCurrentLocale());
        $keywords = metaFields('categories', 'keywords', getCurrentLocale());
        $meta_description = metaFields('categories', 'meta_description', getCurrentLocale());

        //He should be able to see the fields which enable him to edit the category
        $response->assertStatus(200);
        $response->assertSee($name ?? __('categories.name'));
        $response->assertSee($slug ?? __('categories.slug'));
        $response->assertSee($keywords ?? __('categories.keywords'));
        $response->assertSee($meta_description ?? __('categories.meta_description'));

        $response->assertSee($category->name);
        $response->assertSee($category->slug);
    }

    /**
     * Method to ensure that the user can add category.
     *
     * @return void
     */

    public function testUserCanAddCategory()
    {
        $dataToSave= [];
        foreach (languages() as $key => $language) {
            $dataToSave['name_'.$language->local] = $this->faker->sentence(1);
            $dataToSave['slug_'.$language->local] = $this->faker->unique()->slug(1);
            $dataToSave['keywords_'.$language->local] = $this->faker->sentence;
            $dataToSave['meta_description_'.$language->local] = $this->faker->sentence;
            $dataToSave['language_id'] = $language->id;
        }


        // dd($dataToSave);
        //When user submits post request to create category endpoint
        $response= $this->post('/admin/categories',array_merge( $dataToSave, ['_token'=> csrf_token()] ) );

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

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

        //It gets stored in the database
        $this->assertDatabaseHas('category_descriptions',[
            'name'=> $dataToSave['name_'.getCurrentLocale()],
            'slug'=> $dataToSave['slug_'.getCurrentLocale()],
            'language_id'=> $dataToSave['language_id']
        ]
        );

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

        // Category appears in the categories page
        $response = $this->get('/admin/categories/grid');

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

    /**
     * Method to ensure that the user can Edit category.
     *
     * @return void
     */

    public function testUserCanUpdateCategory()
    {
        //And a category object
        $category = factory('App\CategoryDescription')->create()->toArray();
        $dataToSave= [];
        foreach (languages() as $key => $language) {
            $dataToSave['name_'.$language->local] = $this->faker->sentence(1);
            $dataToSave['slug_'.$language->local] = $this->faker->unique()->slug(1);
            $dataToSave['keywords_'.$language->local] = $this->faker->sentence;
            $dataToSave['meta_description_'.$language->local] = $this->faker->sentence;
            $dataToSave['language_id'] = $language->id;
        }
        $newTitle= 'New Category edittion';
        $dataToSave['name_'.getCurrentLocale()] = $newTitle;
        // dd($dataToSave);

        //When user submits post request to edit category endpoint
        $response= $this->put("/admin/categories/{$category['category_id']}",array_merge( $dataToSave, ['_token'=> csrf_token()] ) );

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

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

        //It gets stored in the database
        $this->assertDatabaseHas('category_descriptions',[
                'name'=> $dataToSave['name_'.getCurrentLocale()],
                'slug'=> $dataToSave['slug_'.getCurrentLocale()],
                'language_id'=> $dataToSave['language_id']
            ]
        );
        // Session success message
        $response->assertSessionHas('message', __('dashboard.saveDone'));

        // Category appears in the categories page
        $response = $this->get('/admin/categories/grid');

        //He should be able to read the category
        $response->assertSee($newTitle);
    }

    /**
     * Method to ensure that the user can send the category to trash.
     *
     * @return void
     */

    public function testCategoriesTrash()
    {
        $category = factory('App\CategoryDescription')->create();

        //When the user hit's the endpoint to delete the category
        $this->delete("/admin/categories/{$category->category_id}", ['_token'=> csrf_token()]);

        //The category should be deleted from the database.
        $this->assertSoftDeleted('categories',['id'=> $category->category_id]);
    }

    /**
     * Method to ensure that the user can delete the category from database.
     *
     * @return void
     */

    public function testCategoriesDelete()
    {
        $category = factory('App\CategoryDescription')->create();

        // user sent the category to trash first, as he can not delete it from the first click
        $this->delete("/admin/categories/{$category->category_id}", ['_token'=> csrf_token()]);

        //When the user hit's the endpoint to delete the category
        $this->delete("/admin/categories/{$category->category_id}", ['_token'=> csrf_token()]);

        //The category should be deleted from the database.

        $this->assertDatabaseMissing('categories',['id'=> $category->category_id]);

        $this->assertDatabaseMissing('category_descriptions',['category_id'=> $category->category_id]);
    }

    /**
     * Method to ensure that the user can send multiple categories to trash.
     *
     * @return void
     */

    public function testCategoriesMultiTrash()
    {
        $categories = factory('App\CategoryDescription', 3)->create();
        $ids= [];
        foreach ($categories as $category) {
            $ids[]= $category->category_id;
        }

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

    /**
     * Method to ensure that the user can delete multiple categories.
     *
     * @return void
     */

    public function testCategoriesMultiDelete()
    {
        $categories = factory('App\CategoryDescription', 3)->create();
        $ids= [];
        foreach ($categories as $category) {
            $ids[]= $category->category_id;
        }
        // dd($ids);

        //When the user hit's the endpoint to send the categories to trash
        $this->delete("/admin/categories", ['_token'=> csrf_token(), 'ids'=> $ids]);

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

        //The category should be deleted from the database.

        $this->assertDatabaseMissing('categories',['id'=> $category->category_id]);

        $this->assertDatabaseMissing('category_descriptions',['category_id'=> $category->category_id]);
    }

    /**
     * Method to ensure that the user can restore the category from trash.
     *
     * @return void
     */

    public function testCategoriesRestore()
    {
        $category = factory('App\CategoryDescription')->create();

        //the user send the category to trash
        $this->delete("/admin/categories/{$category->category_id}", ['_token'=> csrf_token()]);

        $this->assertSoftDeleted('categories',['id'=> $category->category_id]);

        //the user restore the category

        $this->put("/admin/categories/restore/{$category->category_id}", ['_token'=> csrf_token()]);

        //The category should be restored .
        $this->assertDatabaseHas('categories',['id'=> $category->category_id, 'deleted_at'=> null]);
    }


    /**
     * Method to ensure that the user can restore multiple categories.
     *
     * @return void
     */

    public function testCategoriesMultiRestore()
    {
        $categories = factory('App\CategoryDescription', 3)->create();
        $ids= [];
        foreach ($categories as $category) {
            $ids[]= $category->category_id;
        }
        // dd($ids);

        //When the user hit's the endpoint to send the categories to trash
        $this->delete("/admin/categories", ['_token'=> csrf_token(), 'ids'=> $ids]);

        // Test last one to ensure softdeleted process done succesfully
        $this->assertSoftDeleted('categories',['id'=> $category->category_id]);

        //When the user hit's the endpoint to restore the categories from the trash
        $this->put("/admin/categories/restore", ['_token'=> csrf_token(), 'ids'=> $ids]);

        // Test last one to ensure restore process done succesfully
        $this->assertDatabaseHas('categories',['id'=> $category->category_id, 'deleted_at'=> null]);

    }
}
