<?php

namespace Tests\Feature\Controllers;

use Mtc\MercuryDataModels\Role;
use Tests\DatabaseTestCase;
use Tests\UserForTenant;

class RoleControllerTest extends DatabaseTestCase
{
    use UserForTenant;

    private function createRole(string $name = 'Test Role'): Role
    {
        return Role::create([
            'name' => $name,
            'guard_name' => 'web',
            'tenant' => null,
        ]);
    }

    public function testUpdateAssignsExistingPermissions()
    {
        $actingUser = $this->getUser();
        $role = $this->createRole();

        $response = $this->actingAs($actingUser)
            ->putJson(route('roles.update', $role, false), [
                'tenant' => 'all',
                'permissions' => ['edit-content', 'view-enquiries'],
            ]);

        $response->assertStatus(200);
        $this->assertEqualsCanonicalizing(
            ['edit-content', 'view-enquiries'],
            $role->fresh()->permissions->pluck('name')->toArray()
        );
    }

    public function testUpdateRejectsUnknownPermissions()
    {
        $actingUser = $this->getUser();
        $role = $this->createRole();

        $response = $this->actingAs($actingUser)
            ->putJson(route('roles.update', $role, false), [
                'tenant' => 'all',
                'permissions' => ['edit-content', 'not-a-real-permission'],
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['permissions.1']);
        $this->assertCount(0, $role->fresh()->permissions);
    }

    public function testUpdateCannotGrantSystemOwnerWithoutSystemOwner()
    {
        $actingUser = $this->getUser();
        $role = $this->createRole();

        $response = $this->actingAs($actingUser)
            ->putJson(route('roles.update', $role, false), [
                'tenant' => 'all',
                'permissions' => ['edit-content', 'system-owner'],
            ]);

        $response->assertStatus(403);
        $this->assertFalse($role->fresh()->hasPermissionTo('system-owner'));
    }

    public function testUpdateCanGrantSystemOwnerAsSystemOwner()
    {
        $actingUser = $this->getUser();
        $actingUser->givePermissionTo('system-owner');
        $actingUser->load('permissions');
        $role = $this->createRole();

        $response = $this->actingAs($actingUser)
            ->putJson(route('roles.update', $role, false), [
                'tenant' => 'all',
                'permissions' => ['system-owner'],
            ]);

        $response->assertStatus(200);
        $this->assertTrue($role->fresh()->hasPermissionTo('system-owner'));
    }

    public function testUpdateCannotRemoveSystemOwnerWithoutSystemOwner()
    {
        $actingUser = $this->getUser();
        $role = $this->createRole();
        $role->givePermissionTo('system-owner');

        $response = $this->actingAs($actingUser)
            ->putJson(route('roles.update', $role, false), [
                'tenant' => 'all',
                'permissions' => ['edit-content'],
            ]);

        $response->assertStatus(403);
        $this->assertTrue($role->fresh()->hasPermissionTo('system-owner'));
    }

    public function testUpdateKeepingSystemOwnerUnchangedIsAllowed()
    {
        $actingUser = $this->getUser();
        $role = $this->createRole();
        $role->givePermissionTo('system-owner');

        $response = $this->actingAs($actingUser)
            ->putJson(route('roles.update', $role, false), [
                'tenant' => 'all',
                'permissions' => ['system-owner', 'edit-content'],
            ]);

        $response->assertStatus(200);
        $this->assertEqualsCanonicalizing(
            ['system-owner', 'edit-content'],
            $role->fresh()->permissions->pluck('name')->toArray()
        );
    }

    public function testStoreCreatesGlobalRole()
    {
        $actingUser = $this->getUser();

        $response = $this->actingAs($actingUser)
            ->postJson(route('roles.store', [], false), [
                'name' => 'Brand New Role',
            ]);

        $response->assertStatus(201);
        $role = Role::query()->where('name', 'Brand New Role')->first();
        $this->assertNotNull($role);
        $this->assertNull($role->tenant);
        $this->assertCount(0, $role->permissions);
    }

    public function testStoreRejectsDuplicateName()
    {
        $actingUser = $this->getUser();

        $response = $this->actingAs($actingUser)
            ->postJson(route('roles.store', [], false), [
                'name' => 'mtc',
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['name']);
    }
}
