<?php

namespace Tests\Api;

use Tests\TestCase;

class ContentPermissionsApiTest extends TestCase
{
    use TestsApi;

    protected string $baseEndpoint = '/api/content-permissions';

    public function test_user_roles_manage_permission_needed_for_all_endpoints()
    {
        $page = $this->entities->page();
        $endpointMap = [
            ['get', "/api/content-permissions/page/{$page->id}"],
            ['put', "/api/content-permissions/page/{$page->id}"],
        ];
        $editor = $this->users->editor();

        $this->actingAs($editor, 'api');
        foreach ($endpointMap as [$method, $uri]) {
            $resp = $this->json($method, $uri);
            $resp->assertStatus(403);
            $resp->assertJson($this->permissionErrorResponse());
        }

        $this->permissions->grantUserRolePermissions($editor, ['restrictions-manage-all']);

        foreach ($endpointMap as [$method, $uri]) {
            $resp = $this->json($method, $uri);
            $this->assertNotEquals(403, $resp->getStatusCode());
        }
    }

    public function test_read_endpoint_shows_expected_detail()
    {
        $page = $this->entities->page();
        $owner = $this->users->newUser();
        $role = $this->users->createRole();
        $this->permissions->addEntityPermission($page, ['view', 'delete'], $role);
        $this->permissions->changeEntityOwner($page, $owner);
        $this->permissions->setFallbackPermissions($page, ['update', 'create']);

        $this->actingAsApiAdmin();
        $resp = $this->getJson($this->baseEndpoint . "/page/{$page->id}");

        $resp->assertOk();
        $resp->assertExactJson([
            'owner' => [
                'id' => $owner->id, 'name' => $owner->name, 'slug' => $owner->slug,
            ],
            'role_permissions' => [
                [
                    'role_id' => $role->id,
                    'view' => true,
                    'create' => false,
                    'update' => false,
                    'delete' => true,
                    'role' => [
                        'id' => $role->id,
                        'display_name' => $role->display_name,
                    ]
                ]
            ],
            'fallback_permissions' => [
                'inheriting' => false,
                'view' => false,
                'create' => true,
                'update' => true,
                'delete' => false,
            ],
        ]);
    }

    public function test_read_endpoint_shows_expected_detail_when_items_are_empty()
    {
        $page = $this->entities->page();
        $page->permissions()->delete();
        $page->owned_by = null;
        $page->save();

        $this->actingAsApiAdmin();
        $resp = $this->getJson($this->baseEndpoint . "/page/{$page->id}");

        $resp->assertOk();
        $resp->assertExactJson([
            'owner' => null,
            'role_permissions' => [],
            'fallback_permissions' => [
                'inheriting' => true,
                'view' => null,
                'create' => null,
                'update' => null,
                'delete' => null,
            ],
        ]);
    }

    public function test_update_endpoint_can_change_owner()
    {
        $page = $this->entities->page();
        $newOwner = $this->users->newUser();

        $this->actingAsApiAdmin();
        $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
            'owner_id' => $newOwner->id,
        ]);

        $resp->assertOk();
        $resp->assertExactJson([
            'owner' => ['id' => $newOwner->id, 'name' => $newOwner->name, 'slug' => $newOwner->slug],
            'role_permissions' => [],
            'fallback_permissions' => [
                'inheriting' => true,
                'view' => null,
                'create' => null,
                'update' => null,
                'delete' => null,
            ],
        ]);
    }

    public function test_update_can_set_role_permissions()
    {
        $page = $this->entities->page();
        $page->owned_by = null;
        $page->save();
        $newRoleA = $this->users->createRole();
        $newRoleB = $this->users->createRole();

        $this->actingAsApiAdmin();
        $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
            'role_permissions' => [
                ['role_id' => $newRoleA->id, 'view' => true, 'create' => false, 'update' => false, 'delete' => false],
                ['role_id' => $newRoleB->id, 'view' => true, 'create' => false, 'update' => true, 'delete' => true],
            ],
        ]);

        $resp->assertOk();
        $resp->assertExactJson([
            'owner' => null,
            'role_permissions' => [
                [
                    'role_id' => $newRoleA->id,
                    'view' => true,
                    'create' => false,
                    'update' => false,
                    'delete' => false,
                    'role' => [
                        'id' => $newRoleA->id,
                        'display_name' => $newRoleA->display_name,
                    ]
                ],
                [
                    'role_id' => $newRoleB->id,
                    'view' => true,
                    'create' => false,
                    'update' => true,
                    'delete' => true,
                    'role' => [
                        'id' => $newRoleB->id,
                        'display_name' => $newRoleB->display_name,
                    ]
                ]
            ],
            'fallback_permissions' => [
                'inheriting' => true,
                'view' => null,
                'create' => null,
                'update' => null,
                'delete' => null,
            ],
        ]);
    }

    public function test_update_can_set_fallback_permissions()
    {
        $page = $this->entities->page();
        $page->owned_by = null;
        $page->save();

        $this->actingAsApiAdmin();
        $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
            'fallback_permissions' => [
                'inheriting' => false,
                'view' => true,
                'create' => true,
                'update' => true,
                'delete' => false,
            ],
        ]);

        $resp->assertOk();
        $resp->assertExactJson([
            'owner' => null,
            'role_permissions' => [],
            'fallback_permissions' => [
                'inheriting' => false,
                'view' => true,
                'create' => true,
                'update' => true,
                'delete' => false,
            ],
        ]);
    }

    public function test_update_can_clear_roles_permissions()
    {
        $page = $this->entities->page();
        $this->permissions->addEntityPermission($page, ['view'], $this->users->createRole());
        $page->owned_by = null;
        $page->save();

        $this->actingAsApiAdmin();
        $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
            'role_permissions' => [],
        ]);

        $resp->assertOk();
        $resp->assertExactJson([
            'owner' => null,
            'role_permissions' => [],
            'fallback_permissions' => [
                'inheriting' => true,
                'view' => null,
                'create' => null,
                'update' => null,
                'delete' => null,
            ],
        ]);
    }

    public function test_update_can_clear_fallback_permissions()
    {
        $page = $this->entities->page();
        $this->permissions->setFallbackPermissions($page, ['view', 'update']);
        $page->owned_by = null;
        $page->save();

        $this->actingAsApiAdmin();
        $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
            'fallback_permissions' => [
                'inheriting' => true,
            ],
        ]);

        $resp->assertOk();
        $resp->assertExactJson([
            'owner' => null,
            'role_permissions' => [],
            'fallback_permissions' => [
                'inheriting' => true,
                'view' => null,
                'create' => null,
                'update' => null,
                'delete' => null,
            ],
        ]);
    }

    public function test_update_can_both_provide_owner_and_fallback_permissions()
    {
        $user = $this->users->viewer();
        $page = $this->entities->page();
        $page->owned_by = null;
        $page->save();

        $this->actingAsApiAdmin();
        $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
            "owner_id" => $user->id,
            'fallback_permissions' => [
                'inheriting' => false,
                'view' => false,
                'create' => false,
                'update' => false,
                'delete' => false,
            ],
        ]);

        $resp->assertOk();
        $this->assertDatabaseHasEntityData('page', ['id' => $page->id, 'owned_by' => $user->id]);
        $this->assertDatabaseHas('entity_permissions', [
            'entity_id' => $page->id,
            'entity_type' => 'page',
            'role_id' => 0,
            'view' => false,
            'create' => false,
            'update' => false,
            'delete' => false,
        ]);
    }
}
