<?php

namespace MintyPHP\Service\User;

use MintyPHP\App\Module\ModuleEventDispatcher;
use MintyPHP\Repository\Access\UserRoleRepositoryInterface;
use MintyPHP\Repository\Org\UserDepartmentRepositoryInterface;
use MintyPHP\Repository\Support\DatabaseSessionRepository;
use MintyPHP\Repository\Tenant\UserTenantRepositoryInterface;
use MintyPHP\Repository\User\UserListQueryRepositoryInterface;
use MintyPHP\Repository\User\UserReadRepositoryInterface;
use MintyPHP\Repository\User\UserWriteRepositoryInterface;
use MintyPHP\Service\Access\AssignableRoleService;
use MintyPHP\Service\Audit\AuditRecorderInterface;
use MintyPHP\Service\Audit\UserLifecycleAuditInterface;

class UserServicesFactory
{
    private ?UserPasswordPolicyService $userPasswordPolicyService = null;
    private ?UserPasswordService $userPasswordService = null;
    private ?UserAvatarService $userAvatarService = null;
    private ?UserAssignmentService $userAssignmentService = null;
    private ?UserTenantContextService $userTenantContextService = null;
    private ?UserAccountService $userAccountService = null;
    private ?UserLifecycleService $userLifecycleService = null;
    private ?UserLifecycleRestoreService $userLifecycleRestoreService = null;

    /**
     * @param \Closure(): AssignableRoleService $assignableRoleServiceFactory Lazy resolver to break circular dependency
     */
    public function __construct(
        private readonly AuditRecorderInterface $auditRecorder,
        private readonly UserLifecycleAuditInterface $userLifecycleAudit,
        private readonly UserRepositoryFactory $userRepositoryFactory,
        private readonly UserGatewayFactory $userGatewayFactory,
        private readonly DatabaseSessionRepository $databaseSessionRepository,
        private readonly \Closure $assignableRoleServiceFactory,
        private readonly ?ModuleEventDispatcher $eventDispatcher = null
    ) {
    }

    public function createUserAccountService(): UserAccountService
    {
        return $this->userAccountService ??= new UserAccountService(
            $this->createUserReadRepository(),
            $this->createUserWriteRepository(),
            $this->createUserListQueryRepository(),
            $this->createUserAssignmentService(),
            $this->createUserPasswordService(),
            $this->createUserSettingsGateway(),
            $this->userGatewayFactory->getTenantScopeService(),
            $this->createUserDirectoryGateway(),
            $this->auditRecorder,
            $this->databaseSessionRepository,
            $this->eventDispatcher
        );
    }

    public function createUserAssignmentService(): UserAssignmentService
    {
        return $this->userAssignmentService ??= new UserAssignmentService(
            $this->createUserWriteRepository(),
            $this->createUserTenantRepository(),
            $this->createUserRoleRepository(),
            $this->createUserDepartmentRepository(),
            $this->createUserDirectoryGateway(),
            $this->userGatewayFactory->createPermissionService(),
            $this->databaseSessionRepository,
            ($this->assignableRoleServiceFactory)()
        );
    }

    public function createUserTenantContextService(): UserTenantContextService
    {
        return $this->userTenantContextService ??= new UserTenantContextService(
            $this->createUserReadRepository(),
            $this->createUserWriteRepository(),
            $this->createUserTenantRepository(),
            $this->userGatewayFactory->getTenantScopeService(),
            $this->createUserDirectoryGateway()
        );
    }

    public function createUserPasswordService(): UserPasswordService
    {
        return $this->userPasswordService ??= new UserPasswordService(
            $this->createUserPasswordPolicyService(),
            $this->createUserWriteRepository()
        );
    }

    public function createUserAvatarService(): UserAvatarService
    {
        return $this->userAvatarService ??= new UserAvatarService();
    }

    public function createUserReadRepository(): UserReadRepositoryInterface
    {
        return $this->userRepositoryFactory->createUserReadRepository();
    }

    public function createUserWriteRepository(): UserWriteRepositoryInterface
    {
        return $this->userRepositoryFactory->createUserWriteRepository();
    }

    public function createUserListQueryRepository(): UserListQueryRepositoryInterface
    {
        return $this->userRepositoryFactory->createUserListQueryRepository();
    }

    public function createUserTenantRepository(): UserTenantRepositoryInterface
    {
        return $this->userRepositoryFactory->createUserTenantRepository();
    }

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

    public function createUserDepartmentRepository(): UserDepartmentRepositoryInterface
    {
        return $this->userRepositoryFactory->createUserDepartmentRepository();
    }

    public function createUserPasswordPolicyService(): UserPasswordPolicyService
    {
        return $this->userPasswordPolicyService ??= new UserPasswordPolicyService();
    }

    public function createUserSettingsGateway(): UserSettingsGateway
    {
        return $this->userGatewayFactory->createUserSettingsGateway();
    }

    public function createUserDirectoryGateway(): UserDirectoryGateway
    {
        return $this->userGatewayFactory->createUserDirectoryGateway();
    }

    public function createUserLifecycleService(): UserLifecycleService
    {
        return $this->userLifecycleService ??= new UserLifecycleService(
            $this->createUserReadRepository(),
            $this->createUserWriteRepository(),
            $this->createUserSettingsGateway(),
            $this->userLifecycleAudit,
            $this->databaseSessionRepository
        );
    }

    public function createUserLifecycleRestoreService(): UserLifecycleRestoreService
    {
        return $this->userLifecycleRestoreService ??= new UserLifecycleRestoreService(
            $this->createUserReadRepository(),
            $this->createUserWriteRepository(),
            $this->userLifecycleAudit,
            $this->databaseSessionRepository,
            $this->createUserSettingsGateway()
        );
    }
}
