<?php

namespace MintyPHP\Service\Auth;

use MintyPHP\Http\CookieStoreInterface;
use MintyPHP\Http\RequestRuntimeInterface;
use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Repository\Support\DatabaseSessionRepository;
use MintyPHP\Service\Audit\AuditServicesFactory;
use MintyPHP\Service\Mail\MailServicesFactory;
use MintyPHP\Service\User\UserServicesFactory;

class AuthServicesFactory
{
    private ?TenantSsoService $tenantSsoService = null;
    private ?MicrosoftOidcStateStoreService $microsoftOidcStateStoreService = null;
    private ?MicrosoftOidcService $microsoftOidcService = null;
    private ?ApiTokenService $apiTokenService = null;
    private ?PasswordResetService $passwordResetService = null;
    private ?EmailVerificationService $emailVerificationService = null;
    private ?RememberMeService $rememberMeService = null;
    private ?AuthService $authService = null;
    private ?SsoUserLinkService $ssoUserLinkService = null;
    private ?AuthSessionTenantContextService $authSessionTenantContextService = null;

    public function __construct(
        private readonly UserServicesFactory $userServicesFactory,
        private readonly AuditServicesFactory $auditServicesFactory,
        private readonly MailServicesFactory $mailServicesFactory,
        private readonly AuthRepositoryFactory $authRepositoryFactory,
        private readonly AuthGatewayFactory $authGatewayFactory,
        private readonly DatabaseSessionRepository $databaseSessionRepository,
        private readonly SessionStoreInterface $sessionStore,
        private readonly CookieStoreInterface $cookieStore,
        private readonly RequestRuntimeInterface $requestRuntime
    ) {
    }

    public function createApiTokenService(): ApiTokenService
    {
        return $this->apiTokenService ??= new ApiTokenService(
            $this->userServicesFactory->createUserReadRepository(),
            $this->authRepositoryFactory->createApiTokenRepository(),
            $this->authGatewayFactory->createAuthSettingsGateway(),
            $this->authGatewayFactory->getTenantScopeService(),
            $this->databaseSessionRepository,
            $this->requestRuntime
        );
    }

    public function createPasswordResetService(): PasswordResetService
    {
        return $this->passwordResetService ??= new PasswordResetService(
            $this->userServicesFactory->createUserReadRepository(),
            $this->authRepositoryFactory->createPasswordResetRepository(),
            $this->userServicesFactory->createUserPasswordService(),
            $this->createRememberMeService(),
            $this->mailServicesFactory->createMailService()
        );
    }

    public function createEmailVerificationService(): EmailVerificationService
    {
        return $this->emailVerificationService ??= new EmailVerificationService(
            $this->userServicesFactory->createUserReadRepository(),
            $this->userServicesFactory->createUserWriteRepository(),
            $this->authRepositoryFactory->createEmailVerificationRepository(),
            $this->mailServicesFactory->createMailService()
        );
    }

    public function createRememberMeService(): RememberMeService
    {
        return $this->rememberMeService ??= new RememberMeService(
            $this->userServicesFactory->createUserReadRepository(),
            $this->userServicesFactory->createUserWriteRepository(),
            $this->authRepositoryFactory->createRememberTokenRepository(),
            $this->authGatewayFactory->createPermissionService(),
            $this->createAuthSessionTenantContextService(),
            $this->sessionStore,
            $this->cookieStore,
            $this->requestRuntime,
            $this->authGatewayFactory->createAuthSettingsGateway()
        );
    }

    public function createAuthService(): AuthService
    {
        return $this->authService ??= new AuthService(
            $this->userServicesFactory->createUserReadRepository(),
            $this->userServicesFactory->createUserWriteRepository(),
            $this->userServicesFactory->createUserAccountService(),
            $this->userServicesFactory->createUserTenantContextService(),
            $this->createRememberMeService(),
            $this->createEmailVerificationService(),
            $this->authGatewayFactory->createPermissionService(),
            $this->createTenantSsoService(),
            $this->createAuthSessionTenantContextService(),
            $this->auditServicesFactory->createSystemAuditService(),
            $this->sessionStore
        );
    }

    public function createSsoUserLinkService(): SsoUserLinkService
    {
        return $this->ssoUserLinkService ??= new SsoUserLinkService(
            $this->userServicesFactory->createUserReadRepository(),
            $this->userServicesFactory->createUserWriteRepository(),
            $this->userServicesFactory->createUserAssignmentService(),
            $this->userServicesFactory->createUserTenantRepository(),
            $this->authGatewayFactory->createAuthSettingsGateway(),
            $this->createTenantSsoService(),
            $this->userServicesFactory->createUserAvatarService(),
            $this->authGatewayFactory->createAuthExternalIdentityGateway()
        );
    }

    public function createTenantSsoService(): TenantSsoService
    {
        return $this->tenantSsoService ??= new TenantSsoService(
            $this->authGatewayFactory->createAuthTenantGateway(),
            $this->authRepositoryFactory->createTenantMicrosoftAuthRepository(),
            $this->authGatewayFactory->createAuthSettingsGateway(),
            $this->authGatewayFactory->createAuthCryptoGateway()
        );
    }

    public function createMicrosoftOidcStateStore(): MicrosoftOidcStateStoreService
    {
        return $this->microsoftOidcStateStoreService ??= new MicrosoftOidcStateStoreService($this->sessionStore);
    }

    public function createMicrosoftOidcService(): MicrosoftOidcService
    {
        return $this->microsoftOidcService ??= new MicrosoftOidcService(
            $this->createTenantSsoService(),
            $this->authGatewayFactory->createAuthTenantGateway(),
            $this->createOidcHttpGateway(),
            $this->createMicrosoftOidcStateStore()
        );
    }

    private function createOidcHttpGateway(): OidcHttpGateway
    {
        return new OidcHttpGateway();
    }

    private function createAuthSessionTenantContextService(): AuthSessionTenantContextService
    {
        return $this->authSessionTenantContextService ??= new AuthSessionTenantContextService(
            $this->userServicesFactory->createUserTenantContextService(),
            $this->userServicesFactory->createUserSavedFilterService(),
            $this->sessionStore
        );
    }
}
