<?php

namespace NoahVet\Reef\Infrastructure\Security\IAM\Transformer;

use NoahVet\Reef\Domain\Security\Model\Resource;
use NoahVet\Reef\Domain\Security\Model\ResourceGroup;
use NoahVet\Reef\Domain\Security\Policy\PolicyResult;
use NoahVet\Reef\Domain\Security\Policy\PolicyResultGrant;
use NoahVet\Reef\Iam\Model\GrantedPermissionShort;
use NoahVet\Reef\Iam\Model\PolicyResultPost;

class PolicyResultTransformer implements PolicyResultTransformerInterface
{
    /**
     * @return GrantedPermissionShort[]
     */
    #[\Override]
    public function resultGrantToGrantedPermissions(
        Resource|ResourceGroup $resource,
        PolicyResultGrant $resultGrant,
    ): array {
        $allowed = \array_map(
            static fn (string $permission): GrantedPermissionShort => (new GrantedPermissionShort())
                    ->setResource((string) $resource)
                    ->setPrincipal($resultGrant->getPrincipal())
                    ->setPermission($permission)
                    ->setGrantType(1),
            $resultGrant->getAllow(),
        );

        $denied = \array_map(
            static fn (string $permission): GrantedPermissionShort => (new GrantedPermissionShort())
                    ->setResource((string) $resource)
                    ->setPrincipal($resultGrant->getPrincipal())
                    ->setPermission($permission)
                    ->setGrantType(-1),
            $resultGrant->getDeny(),
        );

        return \array_merge($allowed, $denied);
    }

    #[\Override]
    public function toApiDto(PolicyResult $policyResult): PolicyResultPost
    {
        $ret = new PolicyResultPost();

        $ret->setName($policyResult->getPolicyName());
        $policySubject = $policyResult->getSubject();
        $ret->setSubject($policySubject instanceof Resource ? $policySubject->getResourceId() : $policySubject->getGroupId());
        $ret->setEtag($policyResult->etag ?? '');

        $grants = \array_map(
            fn (PolicyResultGrant $resultGrant): array => $this->resultGrantToGrantedPermissions(
                $policyResult->getSubject(),
                $resultGrant,
            ),
            $policyResult->getGrants(),
        );

        if (empty($grants)) {
            $ret->setGrants([]);
        } else {
            $ret->setGrants(\array_values(\array_merge(...$grants)));
        }

        return $ret;
    }
}
