<?php

namespace MintyPHP\Tests\Service\Access;

use MintyPHP\Service\Access\AuthorizationDecision;
use MintyPHP\Service\Access\AuthorizationPolicyInterface;
use MintyPHP\Service\Access\AuthorizationService;
use PHPUnit\Framework\TestCase;

class AuthorizationServiceTest extends TestCase
{
    public function testReturnsPolicyDecisionForSupportedAbility(): void
    {
        $policy = new class () implements AuthorizationPolicyInterface {
            public function supports(string $ability): bool
            {
                return $ability === 'users.test';
            }

            public function authorize(string $ability, array $context = []): AuthorizationDecision
            {
                return AuthorizationDecision::allow(['ability' => $ability, 'context' => $context]);
            }
        };

        $service = new AuthorizationService([$policy]);
        $decision = $service->authorize('users.test', ['actor_user_id' => 12]);

        $this->assertTrue($decision->isAllowed());
        $this->assertSame('users.test', $decision->attribute('ability'));
        $this->assertSame(['actor_user_id' => 12], $decision->attribute('context'));
    }

    public function testReturnsMissingPolicyDecisionWhenAbilityIsUnknown(): void
    {
        $policy = new class () implements AuthorizationPolicyInterface {
            public function supports(string $ability): bool
            {
                return false;
            }

            public function authorize(string $ability, array $context = []): AuthorizationDecision
            {
                return AuthorizationDecision::allow();
            }
        };

        $service = new AuthorizationService([$policy]);
        $decision = $service->authorize('unknown.ability');

        $this->assertFalse($decision->isAllowed());
        $this->assertSame(500, $decision->status());
        $this->assertSame('authorization_policy_missing', $decision->error());
    }

    public function testAllowReturnsBoolDecisionShortcut(): void
    {
        $policy = new class () implements AuthorizationPolicyInterface {
            public function supports(string $ability): bool
            {
                return $ability === 'users.test';
            }

            public function authorize(string $ability, array $context = []): AuthorizationDecision
            {
                return AuthorizationDecision::allow();
            }
        };

        $service = new AuthorizationService([$policy]);
        $this->assertTrue($service->allow('users.test', ['actor_user_id' => 7]));
        $this->assertFalse($service->allow('users.unknown', ['actor_user_id' => 7]));
    }
}
