<?php

namespace Tests\Feature;

use App\Models\Group;
use App\Models\Organisation;
use App\Models\Suborganisation;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class UserModuleTest extends TestCase
{

    use RefreshDatabase;

    private $organisations = [];
    private $users = [];

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

        // Setup two top level organisations and two suborganisations.
        $this->organisations = [
            'A' => Organisation::create([ 'id' => 1, 'name' => 'A' ]),
            'B' => Organisation::create([ 'id' => 2, 'name' => 'B' ]),
            'C' => Organisation::create([ 'id' => 3, 'name' => 'C' ]),
            'D' => Organisation::create([ 'id' => 4, 'name' => 'D' ]),
            'E' => Organisation::create([ 'id' => 5, 'name' => 'E' ])
        ];

        Suborganisation::insert([
            [ 'parent_id' => 1 , 'child_id' => 3 ],
            [ 'parent_id' => 2 , 'child_id' => 4 ],
            [ 'parent_id' => 2 , 'child_id' => 5 ]
        ]);

        // Setup users
        $group = Group::create([ 'name' => 'Test' ]);

        $default_user = [
            'phone'             => null,
            'password'          => '',
            'group_id'          => $group->id,
        ];

        $this->users = [
            'A' => User::create([ ...$default_user, 'organisation_id' => $this->organisations['A']->id, 'name' => 'A', 'email' => 'creatia+1@globalsecurelayer.com' ]),
            'B1' => User::create([ ...$default_user, 'organisation_id' => $this->organisations['B']->id, 'name' => 'B1', 'email' => 'creatia+2@globalsecurelayer.com' ]),
            'B2' => User::create([ ...$default_user, 'organisation_id' => $this->organisations['B']->id, 'name' => 'B2', 'email' => 'creatia+3@globalsecurelayer.com' ]),
            'C' => User::create([ ...$default_user, 'organisation_id' => $this->organisations['C']->id, 'name' => 'C', 'email' => 'creatia+4@globalsecurelayer.com' ]),
            'D' => User::create([ ...$default_user, 'organisation_id' => $this->organisations['D']->id, 'name' => 'D', 'email' => 'creatia+5@globalsecurelayer.com' ])
        ];

    }

    public function testGetUsers(): void
    {

        // Pretty simple - Make sure we're able to actually retrieve things.

        // Should only have one user
        $scenario_1 = $this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/user?draw=0&start=0&length=50');

        $this->assertTrue($scenario_1->status() === 200, 'Scenario 1 should have returned a 200 status code.');
        $this->assertTrue(sizeof($scenario_1->json()['data']) === 1, 'Scenario 1 should only return one user.');
        $this->assertTrue($scenario_1->json()['data'][0]['user_name'] === 'A', 'Scenario 1 should only return User `A`');

        // Should have two users.
        $scenario_2 = $this->actingAs($this->users['B1'])->withoutMiddleware()->get('/api/user?draw=0&start=0&length=50');

        $this->assertTrue($scenario_2->status() === 200, 'Scenario 2 should have returned a 200 status code.');
        $this->assertTrue(sizeof($scenario_2->json()['data']) === 2, 'Scenario 2 should only return one user.');
        $this->assertTrue(collect($scenario_2->json()['data'])->whereIn('user_name', ['B1', 'B2'])->count() === 2, 'Scenario 2 should only return users `B1` and `B2`.');

    }

    public function testPutUser(): void
    {

        // Create a new user
        $scenario_1 = $this->actingAs($this->users['A'])->withoutMiddleware()->post('/api/user', [
            'name'      => 'A1',
            'email'     => 'creatia+new@globalsecurelayer.com'
        ]);

        $this->assertTrue($scenario_1->status() === 200, 'Scenario 1 should have yielded 200');
        $this->assertTrue(User::where([
            ['name', '=', 'A1'],
            ['email', '=', 'creatia+new@globalsecurelayer.com']
        ])->get()->count() === 1, 'Scenario 1 should have created a user.');

        // Modify an existing user
        $scenario_2 = $this->actingAs($this->users['A'])->withoutMiddleware()->put('/api/user/' . $this->users['A']->id, [
            'name'      => 'A-EDIT',
            'email'     => 'creatia+1@globalsecurelayer.com'
        ]);

        $this->assertTrue($scenario_2->status() === 200, 'Scenario 2 should have yielded 200');
        $this->assertTrue(User::where([
            ['name', '=', 'A-EDIT'],
            ['email', '=', 'creatia+1@globalsecurelayer.com']
        ])->get()->count() === 1, 'Scenario 2 should have modified a user.');

        // Attempt to modify inappropriate user
        $scenario_3 = $this->actingAs($this->users['B1'])->withoutMiddleware()->put('/api/user/' . $this->users['A']->id, [
            'name'      => 'A-EDIT-2',
            'email'     => 'creatia+1@globalsecurelayer.com'
        ]);

        $this->assertTrue($scenario_3->status() === 400, 'Scenario 3 should have yielded 400');
        $this->assertTrue(User::where([
            ['name', '=', 'A-EDIT'],
            ['email', '=', 'creatia+1@globalsecurelayer.com']
        ])->get()->count() === 1, 'Scenario 3 should not have modified a user.');

    }

    public function testDeleteUser(): void
    {
        // Should be able to delete own user.
        $scenario_1 = $this->actingAs($this->users['A'])->withoutMiddleware()->delete('/api/user/' . $this->users['A']->id);

        $this->assertTrue($scenario_1->status() === 200, 'Scenario 1 should have succeeded.');
        $this->assertTrue(User::find($this->users['A']->id) === null, 'Scenario 1 should have deleted the user.');

        // Should not be able to delete someone elses user.
        $scenario_2 = $this->actingAs($this->users['C'])->withoutMiddleware()->delete('/api/user/' . $this->users['B1']->id);

        $this->assertTrue($scenario_2->status() === 500, 'Scenario 2 should have failed.');
        $this->assertTrue(User::find($this->users['B1']->id) !== null, 'Scenario 2 should have deleted the user.');

    }

}
