import { Injectable, NotFoundException, Inject } from "@nestjs/common"; import { Logger } from "nestjs-pino"; import { getErrorMessage } from "@bff/core/utils/error.util"; import { WhmcsConnectionOrchestratorService } from "../connection/services/whmcs-connection-orchestrator.service"; import { WhmcsCacheService } from "../cache/whmcs-cache.service"; import { WhmcsValidateLoginParams, WhmcsAddClientParams, WhmcsClientResponse, } from "../types/whmcs-api.types"; import type { WhmcsAddClientResponse, WhmcsValidateLoginResponse, } from "@customer-portal/domain/customer"; import { Providers as CustomerProviders, type Customer, type CustomerAddress, } from "@customer-portal/domain/customer"; @Injectable() export class WhmcsClientService { constructor( private readonly connectionService: WhmcsConnectionOrchestratorService, private readonly cacheService: WhmcsCacheService, @Inject(Logger) private readonly logger: Logger ) {} /** * Validate client login credentials */ async validateLogin( email: string, password: string ): Promise<{ userId: number; passwordHash: string }> { try { const params: WhmcsValidateLoginParams = { email, password2: password, }; const response = await this.connectionService.validateLogin(params); this.logger.log(`Validated login for email: ${email}`); return { userId: response.userid, passwordHash: response.passwordhash, }; } catch (error) { this.logger.error(`Failed to validate login for email: ${email}`, { error: getErrorMessage(error), }); throw error; } } /** * Get client details by ID */ async getClientDetails(clientId: number): Promise { try { // Try cache first const cached = await this.cacheService.getClientData(clientId); if (cached) { this.logger.debug(`Cache hit for client: ${clientId}`); return cached; } const response = await this.connectionService.getClientDetails(clientId); if (!response || !response.client) { this.logger.error(`WHMCS API did not return client data for client ID: ${clientId}`, { hasResponse: !!response, responseKeys: response ? Object.keys(response) : [], }); throw new NotFoundException(`Client ${clientId} not found`); } const customer = CustomerProviders.Whmcs.transformWhmcsClientResponse(response); await this.cacheService.setClientData(clientId, customer); this.logger.log(`Fetched client details for client ${clientId}`); return customer; } catch (error) { this.logger.error(`Failed to fetch client details for client ${clientId}`, { error: getErrorMessage(error), }); throw error; } } /** * Get client details by email */ async getClientDetailsByEmail(email: string): Promise { try { const response = await this.connectionService.getClientDetailsByEmail(email); if (!response || !response.client) { this.logger.error(`WHMCS API did not return client data for email: ${email}`, { hasResponse: !!response, responseKeys: response ? Object.keys(response) : [], }); throw new NotFoundException(`Client with email ${email} not found`); } const customer = CustomerProviders.Whmcs.transformWhmcsClientResponse(response); await this.cacheService.setClientData(customer.id, customer); this.logger.log(`Fetched client details by email: ${email}`); return customer; } catch (error) { this.logger.error(`Failed to fetch client details by email: ${email}`, { error: getErrorMessage(error), }); throw error; } } /** * Update client details */ async updateClient( clientId: number, updateData: Partial ): Promise { try { await this.connectionService.updateClient(clientId, updateData); // Invalidate client cache after update await this.cacheService.invalidateClientCache(clientId); this.logger.log(`Successfully updated WHMCS client ${clientId}`); } catch (error: unknown) { this.logger.error(`Failed to update WHMCS client ${clientId}`, { error: getErrorMessage(error), updateData, }); throw error; } } /** * Add new client */ async addClient(clientData: WhmcsAddClientParams): Promise<{ clientId: number }> { try { const response = await this.connectionService.addClient(clientData); this.logger.log(`Created new client: ${response.clientid}`); return { clientId: response.clientid }; } catch (error) { this.logger.error(`Failed to create new client`, { error: getErrorMessage(error), email: clientData.email, }); throw error; } } /** * Invalidate cache for a user */ async invalidateUserCache(userId: string): Promise { await this.cacheService.invalidateUserCache(userId); this.logger.log(`Invalidated cache for user ${userId}`); } }