import { z } from 'zod'; import { reportError } from '@/lib/error-handling'; import { BaseService } from '@/lib/service-base'; import { SERVICE_CONFIGS } from '@/lib/service-config'; import { backendMatchSchema, findMatchesQuerySchema, findMatchesResponseSchema, type BackendMatch, type FindMatchesQuery, type FindMatchesResponse, } from '@/schemas/backend/match'; // Additional schemas for matching API const directSymbiosisMatchSchema = z.object({ partner_id: z.string(), partner_name: z.string(), resource: z.string(), resource_flow_id: z.string(), }); const directSymbiosisResponseSchema = z.object({ providers: z.array(directSymbiosisMatchSchema), consumers: z.array(directSymbiosisMatchSchema), }); const updateMatchStatusRequestSchema = z.object({ status: z.string(), actor: z.string(), notes: z.string().optional(), }); // Type exports (keeping for backward compatibility) export interface DirectSymbiosisMatch { partner_id: string; partner_name: string; resource: string; resource_flow_id: string; } export interface DirectSymbiosisResponse { providers: DirectSymbiosisMatch[]; consumers: DirectSymbiosisMatch[]; } /** * Matching Service * Handles all matching-related API operations with improved reliability and type safety */ class MatchingService extends BaseService { constructor() { super(SERVICE_CONFIGS.MATCHING); } /** * Find matches for a resource */ async findMatches(resourceId: string, query?: FindMatchesQuery): Promise { const validatedQuery = query ? this.validateStrict(findMatchesQuerySchema, query, 'findMatches query') : {}; const queryParams = { max_distance_km: validatedQuery.max_distance_km, min_score: validatedQuery.min_score, limit: validatedQuery.limit, }; const result = await this.get( `resource/${resourceId}`, findMatchesResponseSchema, queryParams, { context: `findMatches(${resourceId})`, } ); if (!result.success) { const error = reportError(new Error(result.error?.message || 'Failed to find matches'), { operation: 'findMatches', resourceId, query: validatedQuery, }); throw error; } return result.data; } /** * Get direct symbiosis matches for an organization */ async getDirectSymbiosis(orgId: string): Promise { const result = await this.get( `organization/${orgId}/direct`, directSymbiosisResponseSchema, undefined, { context: `getDirectSymbiosis(${orgId})`, } ); if (!result.success) { const error = reportError( new Error(result.error?.message || 'Failed to get direct symbiosis'), { operation: 'getDirectSymbiosis', orgId } ); throw error; } return result.data; } /** * Get top matches across the platform */ async getTopMatches(limit?: number): Promise { const queryParams = limit ? { limit } : {}; const result = await this.get('top', findMatchesResponseSchema, queryParams, { context: 'getTopMatches', }); if (!result.success) { const error = reportError(new Error(result.error?.message || 'Failed to get top matches'), { operation: 'getTopMatches', limit, }); throw error; } return result.data; } /** * Get match by ID */ async getMatchById(matchId: string): Promise { const result = await this.get(matchId, backendMatchSchema, undefined, { context: `getMatchById(${matchId})`, }); if (!result.success) { const error = reportError(new Error(result.error?.message || 'Failed to get match'), { operation: 'getMatchById', matchId, }); throw error; } return result.data; } /** * Update match status */ async updateMatchStatus( matchId: string, status: string, actor: string, notes?: string ): Promise { const validatedRequest = this.validateStrict( updateMatchStatusRequestSchema, { status, actor, notes, }, 'updateMatchStatus request' ); const result = await this.put(`${matchId}/status`, validatedRequest, z.void(), { context: `updateMatchStatus(${matchId})`, }); if (!result.success) { const error = reportError( new Error(result.error?.message || 'Failed to update match status'), { operation: 'updateMatchStatus', matchId, status, actor, notes } ); throw error; } } } // Create and export service instance const matchingService = new MatchingService(); // Export service instance for direct usage export { matchingService }; // Export service methods directly for cleaner imports export const findMatches = matchingService.findMatches.bind(matchingService); export const getDirectSymbiosis = matchingService.getDirectSymbiosis.bind(matchingService); export const getTopMatches = matchingService.getTopMatches.bind(matchingService); export const getMatchById = (matchId: string) => matchingService.getMatchById(matchId).then((result) => { if (!result.success) { const error = reportError(new Error(result.error?.message || 'Failed to get match'), { operation: 'getMatchById', matchId, }); throw error; } return result.data; }); export const updateMatchStatus = matchingService.updateMatchStatus.bind(matchingService);