<?php

namespace MintyPHP\Tests\Service\Access;

use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Access\RoleAuthorizationPolicy;
use PHPUnit\Framework\TestCase;

class RoleAuthorizationPolicyTest extends TestCase
{
    use AuthorizationPolicyTestSupport;

    public function testAdminViewRequiresRolesViewPermission(): void
    {
        $permissionService = $this->createMock(PermissionService::class);
        $permissionService->expects($this->once())
            ->method('userHas')
            ->with(7, PermissionService::ROLES_VIEW)
            ->willReturn(false);

        $policy = new RoleAuthorizationPolicy($permissionService);
        $decision = $policy->authorize(RoleAuthorizationPolicy::ABILITY_ADMIN_ROLES_VIEW, [
            'actor_user_id' => 7,
        ]);

        $this->assertForbiddenDecision($decision);
    }

    public function testAdminViewIncludesCreateCapability(): void
    {
        $permissionService = $this->permissionGatewayAllowing([
            7 => [PermissionService::ROLES_VIEW, PermissionService::ROLES_CREATE],
        ]);

        $policy = new RoleAuthorizationPolicy($permissionService);
        $decision = $policy->authorize(RoleAuthorizationPolicy::ABILITY_ADMIN_ROLES_VIEW, [
            'actor_user_id' => 7,
        ]);

        $this->assertTrue($decision->isAllowed());
        $this->assertTrue((bool) ($decision->attribute('capabilities', [])['can_create_role'] ?? false));
    }

    public function testAdminCreateRequiresRolesCreatePermission(): void
    {
        $permissionService = $this->createMock(PermissionService::class);
        $permissionService->expects($this->once())
            ->method('userHas')
            ->with(11, PermissionService::ROLES_CREATE)
            ->willReturn(false);

        $policy = new RoleAuthorizationPolicy($permissionService);
        $decision = $policy->authorize(RoleAuthorizationPolicy::ABILITY_ADMIN_ROLES_CREATE, [
            'actor_user_id' => 11,
        ]);

        $this->assertDeniedDecision($decision, 403, 'forbidden');
    }

    public function testEditContextRequiresTargetRoleId(): void
    {
        $permissionService = $this->createMock(PermissionService::class);
        $permissionService->expects($this->never())->method('userHas');

        $policy = new RoleAuthorizationPolicy($permissionService);
        $decision = $policy->authorize(RoleAuthorizationPolicy::ABILITY_ADMIN_ROLES_EDIT_CONTEXT, [
            'actor_user_id' => 5,
            'target_role_id' => 0,
        ]);

        $this->assertDeniedDecision($decision, 403, 'forbidden');
    }

    public function testEditContextReturnsCapabilities(): void
    {
        $permissionService = $this->permissionGatewayAllowing([
            5 => [PermissionService::ROLES_VIEW, PermissionService::ROLES_UPDATE],
        ]);

        $policy = new RoleAuthorizationPolicy($permissionService);
        $decision = $policy->authorize(RoleAuthorizationPolicy::ABILITY_ADMIN_ROLES_EDIT_CONTEXT, [
            'actor_user_id' => 5,
            'target_role_id' => 22,
        ]);

        $capabilities = $decision->attribute('capabilities', []);
        $this->assertTrue($decision->isAllowed());
        $this->assertTrue((bool) ($capabilities['can_edit_role'] ?? false));
        $this->assertFalse((bool) ($capabilities['can_delete_role'] ?? true));
    }

    public function testEditSubmitRequiresRolesUpdatePermission(): void
    {
        $permissionService = $this->permissionGatewayAllowing([
            5 => [PermissionService::ROLES_VIEW],
        ]);

        $policy = new RoleAuthorizationPolicy($permissionService);
        $decision = $policy->authorize(RoleAuthorizationPolicy::ABILITY_ADMIN_ROLES_EDIT_SUBMIT, [
            'actor_user_id' => 5,
            'target_role_id' => 22,
        ]);

        $this->assertForbiddenDecision($decision);
    }

    public function testDeleteRequiresRolesDeletePermission(): void
    {
        $permissionService = $this->createMock(PermissionService::class);
        $permissionService->expects($this->once())
            ->method('userHas')
            ->with(6, PermissionService::ROLES_DELETE)
            ->willReturn(false);

        $policy = new RoleAuthorizationPolicy($permissionService);
        $decision = $policy->authorize(RoleAuthorizationPolicy::ABILITY_ADMIN_ROLES_DELETE, [
            'actor_user_id' => 6,
        ]);

        $this->assertDeniedDecision($decision, 403, 'forbidden');
    }
}
