<?php

namespace MintyPHP\Service\Access;

use MintyPHP\Repository\Access\PermissionRepositoryInterface;
use MintyPHP\Repository\Access\RoleAssignableRoleRepositoryInterface;
use MintyPHP\Repository\Access\RolePermissionRepositoryInterface;
use MintyPHP\Repository\Access\UserRoleRepositoryInterface;

class AccessServicesFactory
{
    private ?AccessPolicyFactory $accessPolicyFactory = null;
    private \Closure $accessPolicyFactoryResolver;

    public function __construct(
        private readonly AccessRepositoryFactory $accessRepositoryFactory,
        private readonly AccessGatewayFactory $accessGatewayFactory,
        callable $accessPolicyFactoryResolver
    ) {
        $this->accessPolicyFactoryResolver = \Closure::fromCallable($accessPolicyFactoryResolver);
    }

    public function createPermissionRepository(): PermissionRepositoryInterface
    {
        return $this->accessRepositoryFactory->createPermissionRepository();
    }

    public function createRolePermissionRepository(): RolePermissionRepositoryInterface
    {
        return $this->accessRepositoryFactory->createRolePermissionRepository();
    }

    public function createUserRoleRepository(): UserRoleRepositoryInterface
    {
        return $this->accessRepositoryFactory->createUserRoleRepository();
    }

    public function createRoleAssignableRoleRepository(): RoleAssignableRoleRepositoryInterface
    {
        return $this->accessRepositoryFactory->createRoleAssignableRoleRepository();
    }

    public function createPermissionService(): PermissionService
    {
        return $this->accessGatewayFactory->createPermissionService();
    }

    public function createUserAuthorizationPolicy(): UserAuthorizationPolicy
    {
        return $this->accessPolicyFactory()->createUserAuthorizationPolicy();
    }

    public function createRoleAuthorizationPolicy(): RoleAuthorizationPolicy
    {
        return $this->accessPolicyFactory()->createRoleAuthorizationPolicy();
    }

    public function createPermissionAuthorizationPolicy(): PermissionAuthorizationPolicy
    {
        return $this->accessPolicyFactory()->createPermissionAuthorizationPolicy();
    }

    public function createSettingsAuthorizationPolicy(): SettingsAuthorizationPolicy
    {
        return $this->accessPolicyFactory()->createSettingsAuthorizationPolicy();
    }

    public function createTenantAuthorizationPolicy(): TenantAuthorizationPolicy
    {
        return $this->accessPolicyFactory()->createTenantAuthorizationPolicy();
    }

    public function createDepartmentAuthorizationPolicy(): DepartmentAuthorizationPolicy
    {
        return $this->accessPolicyFactory()->createDepartmentAuthorizationPolicy();
    }

    public function createAuthorizationService(): AuthorizationService
    {
        return $this->accessPolicyFactory()->createAuthorizationService();
    }

    private function accessPolicyFactory(): AccessPolicyFactory
    {
        if ($this->accessPolicyFactory !== null) {
            return $this->accessPolicyFactory;
        }

        $factory = ($this->accessPolicyFactoryResolver)();
        if (!$factory instanceof AccessPolicyFactory) {
            throw new \RuntimeException('Access policy resolver must return AccessPolicyFactory');
        }
        return $this->accessPolicyFactory = $factory;
    }
}
