import { Injectable } from '@nestjs/common'; import { InquiryType } from '../common/enums/inquiry-type.enum'; import { InquiryStatus } from '../common/enums/inquiry-status.enum'; import { ProviderName } from '../common/enums/provider-name.enum'; import { BaseInquiryResponseDto } from '../common/dto/base-inquiry-response.dto'; import { NormalizedErrorDto } from '../common/dto/normalized-error.dto'; import { generateTrackingCode } from '../common/helpers/tracking-code.helper'; import { buildInquiryResponse } from '../common/helpers/inquiry-response.helper'; import { InquiryException } from '../common/exceptions/inquiry.exception'; import { InquiryLogService } from '../logging/inquiry-log.service'; import { LegacyInquiryPayload, PersonInquiryPayload, PersonInquiryResult, } from '../providers/shared/legacy-api.provider.abstract'; import { ProviderOrchestratorService } from '../providers/strategy/provider-orchestrator.service'; import { PersonInquiryRequestDto } from './dto/person-inquiry-request.dto'; import { PersonInquiryDataDto } from './dto/person-inquiry-data.dto'; @Injectable() export class InquiryService { constructor( private readonly orchestrator: ProviderOrchestratorService, private readonly inquiryLogService: InquiryLogService, ) {} async inquirePerson( dto: PersonInquiryRequestDto, requestId: string, ): Promise> { return this.inquire( InquiryType.PERSON, { nationalCode: dto.nationalCode, birthDate: dto.birthDate, dateHasPostfix: dto.dateHasPostfix, }, requestId, ) as unknown as Promise>; } async inquire( inquiryType: InquiryType, payload: LegacyInquiryPayload, requestId: string, ): Promise>> { const trackingCode = generateTrackingCode(); const start = Date.now(); try { const result = await this.executeInquiry( inquiryType, payload, requestId, trackingCode, ); const response = buildInquiryResponse({ success: true, provider: result.provider, trackingCode, message: `${this.getInquiryLabel(inquiryType)} completed successfully`, duration: result.duration, data: this.toResponseData(result.data), }); await this.persistLog({ inquiryType, provider: result.provider, requestPayload: payload, responsePayload: response.data ?? undefined, status: InquiryStatus.SUCCESS, duration: result.duration, requestId, trackingCode, }); return response; } catch (error) { const duration = Date.now() - start; const { normalized, provider } = this.extractFailure(error); const response = buildInquiryResponse({ success: false, provider: provider ?? 'GATEWAY', trackingCode, message: normalized.message, duration, error: normalized, }); await this.persistLog({ inquiryType, provider: (provider as ProviderName | undefined) ?? ProviderName.HAMTA, requestPayload: payload, status: InquiryStatus.FAILURE, duration, requestId, trackingCode, error: normalized as unknown as Record, }).catch(() => undefined); return response; } } private async executeInquiry( inquiryType: InquiryType, payload: TRequest, requestId: string, trackingCode: string, ) { return this.orchestrator.executeWithFallback(inquiryType, payload, { requestId, trackingCode, }); } private toResponseData(result: unknown): Record { if (this.isPersonInquiryResult(result)) { const raw = result.raw && typeof result.raw === 'object' && !Array.isArray(result.raw) ? (result.raw as Record) : {}; return { nationalCode: result.nationalCode, birthDate: result.birthDate, ...(result.fullName ? { fullName: result.fullName } : {}), ...raw, }; } if (result && typeof result === 'object' && 'raw' in result) { const raw = (result as { raw: unknown }).raw; return raw && typeof raw === 'object' ? (raw as Record) : { raw }; } return result && typeof result === 'object' ? (result as Record) : { raw: result }; } private isPersonInquiryResult(result: unknown): result is PersonInquiryResult { return ( typeof result === 'object' && result !== null && 'nationalCode' in result && 'birthDate' in result ); } private getInquiryLabel(inquiryType: InquiryType): string { return inquiryType.replace(/_INQUIRY$/, '').toLowerCase().replace(/_/g, ' '); } private extractFailure(error: unknown): { normalized: NormalizedErrorDto; provider?: string; } { if (error instanceof InquiryException) { return { normalized: error.normalizedError, provider: error.provider }; } if (error && typeof error === 'object' && 'normalizedError' in error) { return { normalized: (error as { normalizedError: NormalizedErrorDto }).normalizedError, }; } return { normalized: { code: 'INQUIRY_FAILED', message: error instanceof Error ? error.message : 'Inquiry failed', }, }; } private async persistLog( input: Parameters[0], ): Promise { await this.inquiryLogService.create(input); } }