<?php

declare(strict_types=1);

namespace NoahVet\Reef\Phpunit\Security\ResourceType;

use NoahVet\Reef\Exception\NoBearerTokenException;
use NoahVet\Reef\Exception\PermissionFetchException;
use NoahVet\Reef\Phpunit\Fixture\FixtureRepository;
use NoahVet\Reef\Security\IAM\Model\ResourceGroupWithMembers;
use NoahVet\Reef\Security\IAM\Model\ResourceType;
use NoahVet\Reef\Security\ResourceType\ResourceCollectionPermission;
use NoahVet\Reef\Security\ResourceType\ResourceCollectionPermissionFetcherInterface;

class MockedResourceCollectionPermissionFetcher implements ResourceCollectionPermissionFetcherInterface
{
    public function __construct(
        protected ?string $reefServiceToken,
        protected FixtureRepository $fixtureRepository,
    ) {
    }

    public function fetch(
        ResourceType $resourceType,
        bool $expandGroups = true,
        ?string $bearerToken = null,
        bool $tokenRemap = true,
    ): ResourceCollectionPermission {
        $token = $bearerToken ?? $this->reefServiceToken;

        if (null === $token) {
            throw new NoBearerTokenException();
        }

        $tokenFixture = $this->fixtureRepository->findByOAuthToken($token);

        if (!$tokenFixture) {
            throw new PermissionFetchException();
        }

        // Find the permissions for all resources
        $allPermissions = [];
        $groupPermissions = [];
        $resourcePermissions = [];

        foreach ($tokenFixture->getAllPermissions() as $permissionFixture) {
            if ($permissionFixture->getResourceType()->getSlug() !== $resourceType->getSlug()) {
                continue;
            }

            $target = $permissionFixture->getTarget();

            if ($target instanceof ResourceGroupWithMembers && '*' === $target->getGroupId()) {
                $allPermissions = $permissionFixture->getAllowedPermission();
            } elseif ($target instanceof ResourceGroupWithMembers) {
                if ($expandGroups) {
                    foreach ($target->getMembers() as $member) {
                        $resourcePermissions[$member->getResourceId()] = $permissionFixture->getAllowedPermission();
                    }
                } else {
                    $groupPermissions[$target->getGroupId()] = $permissionFixture->getAllowedPermission();
                }
            } else {
                $resourcePermissions[$target->getResourceId()] = $permissionFixture->getAllowedPermission();
            }
        }

        return new ResourceCollectionPermission(
            $resourceType,
            $allPermissions,
            $resourcePermissions,
            $groupPermissions,
        );
    }
}
