<?php

namespace Tests\Feature;

use App\Models\ToDo;
use App\Models\ToDoList;
use App\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class ToDoItemsTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    public function a_user_can_create_a_to_do_list()
    {
        $this->withoutExceptionHandling();
        $this->actingAs($user = factory(User::class)->create(), 'api');
        $toDoList = factory(ToDoList::class)->create(['id' => 123, 'user_id' => $user->id]);

        $response = $this->post('/api/to-do-lists/'. $toDoList->id .'/to-do', [
            'name' => 'Test name to do',
        ])->assertStatus(201);

        $toDo = ToDo::first();

        $this->assertEquals('Test name to do', $toDo->name);
        $this->assertEquals($toDoList->todos[0], $toDo);
        $response->assertJson([
            'data' => [
                'to_do_id' => $toDo->id,
                'attributes' => [
                    'data' => [
                        'name' => $toDo->name,
                        'order' => 1,
                    ]
                ],
            ],
            'links' => [
                'self' => url('/to-do-lists/'.$toDo->toDoList->id),
            ]
        ]);
    }

    /** @test */
    public function to_do_name_are_required()
    {
        $this->actingAs($user = factory(User::class)->create(), 'api');
        $toDoList = factory(ToDoList::class)->create(['user_id' => $user->id]);
        $response = $this->post('/api/to-do-lists/'. $toDoList->id .'/to-do', ['name' => '']);

        $response->assertSessionHasErrors('name');
        $this->assertCount(0, ToDo::all());
    }

    /** @test */
    public function a_to_do_by_to_do_list_can_be_retrieved()
    {
        $this->actingAs($user = factory(User::class)->create(), 'api');
        $toDoList = factory(ToDoList::class)->create(['user_id' => $user->id]);
        $toDoList->toDos()->create([
            'name' => 'Test name to do',
        ]);

        $response = $this->get('/api/to-do-lists/' . $toDoList->id );

        $response->assertJson([
            'data' => [
                'to_do_list_id' => $toDoList->id,
                'attributes' => [
                    'data' => [
                        'name' => $toDoList->name,
                        'last_updated' => $toDoList->updated_at->diffForHumans(),
                        'to_dos' => [
                            'data' => [
                                [
                                    'data' => [
                                        'to_do_id' => $toDoList->toDos[0]->id,
                                        'attributes' => [
                                            'data' => [
                                                'name' => $toDoList->toDos[0]->name,
                                            ]
                                        ]
                                    ]
                                ]
                            ],
                            'to_dos_count' => 1,
                        ]
                    ]
                ],
            ]
        ]);
    }

    /** @test */
    public function a_new_to_do_must_have_order_of_the_previous_to_do()
    {
        $this->actingAs($user = factory(User::class)->create(), 'api');
        $toDoList = factory(ToDoList::class)->create(['id' => 123, 'user_id' => $user->id]);
        $toDo = factory(ToDo::class)->create(['to_do_list_id' => 123]);

        $response = $this->post('/api/to-do-lists/123/to-do', [
            'name' => 'New To Do'
        ])->assertStatus(201);

        $toDo = ToDo::first();
        $newToDo = ToDo::orderBy('id', 'desc')->first();

        $this->assertEquals('New To Do', $newToDo->name);
        $this->assertEquals($toDo->order + 1, $newToDo->order);
    }

    /** @test */
    public function a_second_to_do_as_next_order_of_list()
    {
        $this->actingAs($user = factory(User::class)->create(), 'api');
        $toDoList = factory(ToDoList::class)->create(['id' => 123, 'user_id' => $user->id]);
        $this->post('/api/to-do-lists/123/to-do', ['name' => 'Test name to do']);
        $this->post('/api/to-do-lists/123/to-do', ['name' => 'Test 2 name to do']);
        $this->post('/api/to-do-lists/123/to-do', ['name' => 'Test 3 name to do']);

        $response = $this->get('/api/to-do-lists/' . $toDoList->id );

        $response->assertJson([
            'data' => [
                'to_do_list_id' => $toDoList->id,
                'attributes' => [
                    'data' => [
                        'name' => $toDoList->name,
                        'last_updated' => $toDoList->updated_at->diffForHumans(),
                        'to_dos' => [
                            'data' => [
                                [
                                    'data' => [
                                        'to_do_id' => $toDoList->toDos[0]->id,
                                        'attributes' => [
                                            'data' => [
                                                'name' => $toDoList->toDos[0]->name,
                                                'order' => 1,
                                            ]
                                        ]
                                    ],

                                ],
                                [
                                    'data' => [
                                        'to_do_id' => $toDoList->toDos[1]->id,
                                        'attributes' => [
                                            'data' => [
                                                'name' => $toDoList->toDos[1]->name,
                                                'order' => 2,
                                            ]
                                        ]
                                    ]
                                ],
                                [
                                    'data' => [
                                        'to_do_id' => $toDoList->toDos[2]->id,
                                        'attributes' => [
                                            'data' => [
                                                'name' => $toDoList->toDos[2]->name,
                                                'order' => 3,
                                            ]
                                        ]
                                    ]
                                ]
                            ],
                            'to_dos_count' => 3,
                        ]
                    ]
                ],
            ]
        ]);
    }

    /** @test */
    public function a_to_do_can_be_patch()
    {
        $this->withoutExceptionHandling();
        $this->actingAs($user = factory(User::class)->create(), 'api');
        $toDoList = factory(ToDoList::class)->create(['id' => 123, 'user_id' => $user->id]);
        $toDoList->toDos()->create([
            'name' => 'Test name to do',
            'order' => 10,
        ]);

        $toDoList = $toDoList->fresh();

        $response = $this->patch('/api/to-do-lists/123/to-do/'. $toDoList->toDos[0]->id, [
            'name' => 'To Do update'
        ])->assertStatus(200)
            ->assertJson([
            'data' => [
                'to_do_id' => $toDoList->toDos[0]->id,
                'attributes' => [
                    'data' => [
                        'name' => 'To Do update',
                        'order' => 10,
                    ]
                ]
            ],
            'links' => [
                'self' => url('/to-do-lists/'. $toDoList->id),
            ]
        ]);
    }

    /** @test */
    public function only_the_owner_can_patch_the_to_do()
    {
        $user = factory(User::class)->create();
        $toDoList = factory(ToDoList::class)->create(['id' => 123, 'user_id' => $user->id]);
        $toDo = factory(ToDo::class)->create(['to_do_list_id' => 123, 'name' => 'Test name to do']);

        $this->actingAs($anotherUser = factory(User::class)->create(), 'api');

        $this->patch('/api/to-do-lists/'. $toDoList->id .'/to-do/'. $toDoList->toDos[0]->id, ['name' => 'Name changed'])
            ->assertStatus(403);
    }

    /** @test */
    public function a_to_do_can_changer_of_order()
    {
        $this->withoutExceptionHandling();
        $this->actingAs($user = factory(User::class)->create(), 'api');
        $toDoList = factory(ToDoList::class)->create(['id' => 123, 'user_id' => $user->id]);
        $this->post('/api/to-do-lists/123/to-do', ['name' => 'Test name to do']);
        $toDoReplaced = $this->post('/api/to-do-lists/123/to-do', ['name' => 'Test 2 name to do']);
        $this->post('/api/to-do-lists/123/to-do', ['name' => 'Test 3 name to do']);
        $this->post('/api/to-do-lists/123/to-do', ['name' => 'Test 4 name to do']);
        $todoMove = $this->post('/api/to-do-lists/123/to-do', ['name' => 'Test 5 name to do']);


        $response = $this->patch('/api/to-do-lists/'. $toDoList->id .'/to-do/'. $todoMove['data']['to_do_id'] .'/change', ['new-order' => $toDoReplaced['data']['attributes']['data']['order']])
            ->assertStatus(200)
            ->assertJson([
                'data' => [
                    'to_do_id' => $todoMove['data']['to_do_id'],
                    'attributes' => [
                        'data' => [
                            'order' => $toDoReplaced['data']['attributes']['data']['order'],
                        ]
                    ]
                ],
                'links' => [
                    'self' => url('/to-do-lists/'. $toDoList->id),
                ]
            ]);
    }

    /** @test */
    public function a_to_do_list_can_be_delete()
    {
        $this->withoutExceptionHandling();
        $this->actingAs($user = factory(User::class)->create(), 'api');

        $toDoList = factory(ToDoList::class)->create(['user_id' => $user->id]);
        $toDo = factory(ToDo::class)->create(['to_do_list_id' => $toDoList->id]);

        $response = $this->delete('/api/to-do-lists/'. $toDoList->id . '/to-do/' . $toDo->id);

        $this->assertCount(0, ToDo::all());

        $response->assertStatus(204);
    }

    /** @test */
    public function only_the_owner_can_delete_the_to_do_list()
    {
        $user = factory(User::class)->create();
        $toDoList = factory(ToDoList::class)->create(['user_id' => $user->id]);
        $toDo = factory(ToDo::class)->create(['to_do_list_id' => $toDoList->id]);

        $this->actingAs($anotherUser = factory(User::class)->create(), 'api');

        $response = $this->delete('/api/to-do-lists/'. $toDoList->id . '/to-do/' . $toDo->id);

        $response->assertStatus(403);
    }
}
