import { Inject, Injectable } from '@nestjs/common'; // Core Use Cases import { LoginUseCase, type LoginInput } from '@core/identity/application/use-cases/LoginUseCase'; import { LogoutUseCase } from '@core/identity/application/use-cases/LogoutUseCase'; import { SignupUseCase, type SignupInput } from '@core/identity/application/use-cases/SignupUseCase'; // Core Interfaces and Tokens import { IdentitySessionPort } from '@core/identity/application/ports/IdentitySessionPort'; import { User } from '@core/identity/domain/entities/User'; import type { IUserRepository } from '@core/identity/domain/repositories/IUserRepository'; import type { Logger } from '@core/shared/application'; import { IDENTITY_SESSION_PORT_TOKEN, LOGGER_TOKEN, LOGIN_USE_CASE_TOKEN, LOGOUT_USE_CASE_TOKEN, SIGNUP_USE_CASE_TOKEN, USER_REPOSITORY_TOKEN } from './AuthProviders'; import { AuthenticatedUserDTO, AuthSessionDTO, LoginParams, SignupParams } from './dtos/AuthDto'; import { AuthSessionPresenter } from './presenters/AuthSessionPresenter'; import type { CommandResultDTO } from './presenters/CommandResultPresenter'; import { CommandResultPresenter } from './presenters/CommandResultPresenter'; @Injectable() export class AuthService { constructor( @Inject(LOGGER_TOKEN) private logger: Logger, @Inject(IDENTITY_SESSION_PORT_TOKEN) private identitySessionPort: IdentitySessionPort, @Inject(USER_REPOSITORY_TOKEN) private userRepository: IUserRepository, @Inject(LOGIN_USE_CASE_TOKEN) private readonly loginUseCase: LoginUseCase, @Inject(SIGNUP_USE_CASE_TOKEN) private readonly signupUseCase: SignupUseCase, @Inject(LOGOUT_USE_CASE_TOKEN) private readonly logoutUseCase: LogoutUseCase, private readonly authSessionPresenter: AuthSessionPresenter, private readonly commandResultPresenter: CommandResultPresenter, ) {} private mapUserToAuthenticatedUserDTO(user: User): AuthenticatedUserDTO { return { userId: user.getId().value, email: user.getEmail() ?? '', displayName: user.getDisplayName() ?? '', }; } private buildAuthSessionDTO(token: string, user: AuthenticatedUserDTO): AuthSessionDTO { return { token, user: { userId: user.userId, email: user.email, displayName: user.displayName, }, }; } async getCurrentSession(): Promise { this.logger.debug('[AuthService] Attempting to get current session.'); const coreSession = await this.identitySessionPort.getCurrentSession(); if (!coreSession) { return null; } const user = await this.userRepository.findById(coreSession.user.id); if (!user) { this.logger.warn( `[AuthService] Session found for user ID ${coreSession.user.id}, but user not found in repository.`, ); await this.identitySessionPort.clearSession(); return null; } const authenticatedUserDTO = this.mapUserToAuthenticatedUserDTO(User.fromStored(user)); const apiSession = this.buildAuthSessionDTO(coreSession.token, authenticatedUserDTO); return apiSession; } async signupWithEmail(params: SignupParams): Promise { this.logger.debug(`[AuthService] Attempting signup for email: ${params.email}`); const input: SignupInput = { email: params.email, password: params.password, displayName: params.displayName, }; const result = await this.signupUseCase.execute(input); if (result.isErr()) { const error = result.unwrapErr(); throw new Error(error.details?.message ?? 'Signup failed'); } const userDTO = this.authSessionPresenter.getResponseModel(); const coreUserDTO = { id: userDTO.userId, displayName: userDTO.displayName, email: userDTO.email, }; const session = await this.identitySessionPort.createSession(coreUserDTO); return { token: session.token, user: userDTO, }; } async loginWithEmail(params: LoginParams): Promise { this.logger.debug(`[AuthService] Attempting login for email: ${params.email}`); const input: LoginInput = { email: params.email, password: params.password, }; const result = await this.loginUseCase.execute(input); if (result.isErr()) { const error = result.unwrapErr(); throw new Error(error.details?.message ?? 'Login failed'); } const userDTO = this.authSessionPresenter.getResponseModel(); const coreUserDTO = { id: userDTO.userId, displayName: userDTO.displayName, email: userDTO.email, }; const session = await this.identitySessionPort.createSession(coreUserDTO); return { token: session.token, user: userDTO, }; } async logout(): Promise { this.logger.debug('[AuthService] Attempting logout.'); const result = await this.logoutUseCase.execute(); if (result.isErr()) { const error = result.unwrapErr(); throw new Error(error.details?.message ?? 'Logout failed'); } return this.commandResultPresenter.getResponseModel(); } }