<?php

namespace Tests\Feature;

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

class VisitorMessageTest 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 visitorMessages panel.
     *
     * @return void
     */
    public function testUserCanAccessVisitorMessagesPanel() :void
    {

        // VisitorMessages route which visit by user
        $response = $this->get(route('visitorMessages.index'));

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

    /**
     * Method to ensure that the user can read all visitorMessages.
     *
     * @return void
     */
    public function testUserCanReadAllVisitorMessages() :void
    {
        //Given we have visitor message and visitor message description in the database
        $visitorMessage = factory(VisitorMessage::class)->create();

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

        //He should be able to read the visitor message
        $response->assertSee($visitorMessage->subject);

    }

    /**
     * Method to ensure that the create form route exists.
     *
     * @return void
     */
    public function testUserCanCreateVisitorMessage() :void
    {
        //When user the new newsletter message form route
        $response = $this->get(route('visitorMessages.create'));

        //He should be able to see the fields which enable him to add new visitor message
        $response->assertStatus(200);
        $send_to = metaFields('visitorMessages', 'send_to', getCurrentLocale());
        $message = metaFields('visitorMessages', 'message', getCurrentLocale());

        $response->assertSee($send_to ?? __('visitorMessages.send_to'));
        $response->assertSee($message ?? __('visitorMessages.message'));
    }

    /**
     * Method to ensure that the update form route exists.
     *
     * @return void
     */
    public function testUserCanEditVisitorMessage() :void
    {
        //Given we have visitor message in the database
        $visitorMessage = factory(VisitorMessage::class)->create();
        //When user visit the visitorMessages form route
        $response = $this->get(route('visitorMessages.edit', $visitorMessage->id));

        //He should be able to see the fields which enable him to edit the visitor message
        $response->assertStatus(200);
        $send_to = metaFields('visitorMessages', 'send_to', getCurrentLocale());
        $message = metaFields('visitorMessages', 'message', getCurrentLocale());
        $response->assertSee($send_to ?? __('visitorMessages.send_to'));
        $response->assertSee($message ?? __('visitorMessages.message'));

        $response->assertSee($visitorMessage->email);

    }

    /**
     * Method to ensure that the user can add visitor message.
     *
     * @return void
     */
    public function testUserCanAddVisitorMessage() :void
    {
        $visitorMessage = factory(VisitorMessage::class)->create();

        $dataToSave = [
            'reply' => $this->faker->paragraph,
            'visitor_email' => $visitorMessage->email,
        ];

        //When user submits post request to create visitor message endpoint
        $response= $this->post(route('visitorMessages.store'), array_merge( $dataToSave, ['_token'=> csrf_token()] ) );
        // The redirect response header status is 302
        $response->assertStatus(302);

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


        //It gets stored in the database
        $this->assertDatabaseHas('visitor_message_replies',
            [
                'reply' => $dataToSave['reply'],
                'visitor_email' => $dataToSave['visitor_email'],
            ]);

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

        // newsletter appears in the VisitorMessages panel
        $response = $this->get(route('visitorMessages.grid'));

        //He should be able to read the visitor message
        $response->assertSee($visitorMessage->subject);

        // user should be able to read this visitor message
        $response = $this->get(route('visitorMessages.edit', $visitorMessage->id));
        $response->assertSee($dataToSave['visitor_email']);


    }

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

        $visitorMessage = factory(VisitorMessage::class)->create();

        $dataToSave = [
            'reply' => $this->faker->paragraph,
            'visitor_email' => $visitorMessage->email,
        ];

        //When user submits post request to edit visitor message endpoint
        $response= $this->put(route('visitorMessages.update', $visitorMessage->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/visitorMessages');;

        //It gets stored in the database
        $this->assertDatabaseHas('visitor_message_replies',
            [
                'reply' => $dataToSave['reply'],
                'visitor_email' => $dataToSave['visitor_email'],
            ]);


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

        // newsletter appears in the VisitorMessages panel
        $response = $this->get(route('visitorMessages.grid'));

        //He should be able to read the visitor message
        $response->assertSee($visitorMessage->subject);

        // user should be able to read this visitor message
        $response = $this->get(route('visitorMessages.edit', $visitorMessage->id));
        $response->assertSee($dataToSave['reply']);
        $response->assertSee($dataToSave['visitor_email']);
    }

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

        //Add a visitor message object
        $visitorMessage = factory(VisitorMessage::class)->create();

        //When the user hit's with endpoint to delete the visitor message
        $this->delete(route('visitorMessages.destroy', $visitorMessage->id), ['_token'=> csrf_token()]);

        //The visitor message should be deleted from the database.
        $this->assertSoftDeleted('visitor_messages',['id'=> $visitorMessage->id]);
    }

    /**
     * Method to ensure that the user can delete the visitor message from database.
     *
     * @return void
     */
    public function testVisitorMessagesDelete() :void
    {
        //Add a visitor message object
        $visitorMessage =  factory(VisitorMessage::class)->create();

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

        //When the user hit's the endpoint to delete the category
        $this->delete(route('visitorMessages.destroy', $visitorMessage->id), ['_token'=> csrf_token()]);

        //The visitor message should be deleted from the database.

        $this->assertDatabaseMissing('visitor_messages',['id'=> $visitorMessage->id]);

    }

    /**
     * Method to ensure that the user can send multiple visitorMessages to trash.
     *
     * @return void
     */
    public function testVisitorMessagesMultiTrash() :void
    {
        //Add a visitor message object
        $visitorMessages = factory(VisitorMessage::class, 3)->create();

        $ids= $visitorMessages->pluck('id')->toArray();

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

    /**
     * Method to ensure that the user can delete multiple visitorMessages.
     *
     * @return void
     */
    public function testVisitorMessagesMultiDelete() :void
    {
        //Add a visitor message object
        $visitorMessages = factory(VisitorMessage::class, 3)->create();

        $ids= $visitorMessages->pluck('id')->toArray();

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

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

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

    }

    /**
     * Method to ensure that the user can restore the visitor message from trash.
     *
     * @return void
     */
    public function testVisitorMessagesRestore() :void
    {
        //Add a visitor message object
        $visitorMessages = factory(VisitorMessage::class)->create();

        //the user send the visitor message to trash
        $this->delete(route('visitorMessages.destroy', $visitorMessages->id), ['_token'=> csrf_token()]);

        $this->assertSoftDeleted('visitor_messages',['id'=> $visitorMessages->id]);

        //the user restore the visitor message
        $this->put(route('visitorMessages.restore', $visitorMessages->id), ['_token'=> csrf_token()]);

        //The visitor message should be restored .
        $this->assertDatabaseHas('visitor_messages',['id'=> $visitorMessages->id, 'deleted_at'=> null]);
    }

    /**
     * Method to ensure that the user can restore multiple visitorMessages.
     *
     * @return void
     */
    public function testVisitorMessagesMultiRestore() :void
    {
        //Add a visitor message object
        $visitorMessages = factory(VisitorMessage::class, 3)->create();

        $ids = $visitorMessages->pluck('id')->toArray();

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

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

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

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

    }
}
