<?php

namespace NoahVet\Reef\Phpunit\Security;

use NoahVet\Reef\Domain\Security\Model\Resource;
use NoahVet\Reef\Domain\Security\Model\ResourceType;
use NoahVet\Reef\Domain\Security\Port\PermissionCheckerInterface;
use NoahVet\Reef\Phpunit\Fixture\FixtureRepository;
use NoahVet\Reef\Phpunit\Fixture\PermissionFixture;

/**
 * Test double for PermissionCheckerInterface.
 * Allows testing Application use cases and Infrastructure adapters without an IAM API.
 */
class MockedPermissionChecker implements PermissionCheckerInterface
{
    public function __construct(
        private readonly FixtureRepository $fixtureRepository,
    ) {
    }

    #[\Override]
    public function check(Resource|ResourceType $subject, array $permissions, string $bearerToken): bool
    {
        $fixture = $this->fixtureRepository->findByOAuthToken($bearerToken);

        if (null === $fixture) {
            return false;
        }

        if ($fixture->isSuperAdmin()) {
            return true;
        }

        if ($subject instanceof ResourceType) {
            $matching = \array_reduce(
                $fixture->getPermissionsByResourceType((string) $subject),
                static fn (bool $carry, PermissionFixture $pf): bool => $carry || \count(\array_intersect($pf->getAllowedPermission(), $permissions)) === \count($permissions),
                false,
            );

            return $matching;
        }

        $pf = $fixture->getPermissions((string) $subject);

        if (null === $pf) {
            return false;
        }

        return \count(\array_intersect($pf->getAllowedPermission(), $permissions)) === \count($permissions);
    }

    #[\Override]
    public function checkGroup(string $groupSlug, string $bearerToken): bool
    {
        $fixture = $this->fixtureRepository->findByOAuthToken($bearerToken);

        if (null === $fixture) {
            return false;
        }

        if ($fixture->isSuperAdmin() && \str_starts_with($groupSlug, 'reef:iam:principals:')) {
            return true;
        }

        return false;
    }
}
