import { formatPhone } from '~/utils/formatters/phone'; export interface ConstructeurTelephoneSummary { numero?: string | null; label?: string | null; } export interface ConstructeurSummary { id: string; name?: string | null; email?: string | null; // Legacy single-phone string: still exposed by the machine-structure normalization. phone?: string | null; // Multi-phone list: exposed by the /constructeurs API resource. telephones?: ConstructeurTelephoneSummary[] | null; } type ConstructeurPhoneSource = { phone?: string | null; telephones?: ConstructeurTelephoneSummary[] | null; } | null | undefined; export const constructeurPhones = ( constructeur: ConstructeurPhoneSource, ): Array<{ numero: string; label: string | null }> => { if (!constructeur) { return []; } const list = Array.isArray(constructeur.telephones) ? constructeur.telephones .filter((t): t is ConstructeurTelephoneSummary => Boolean(t && t.numero && String(t.numero).trim())) .map(t => ({ numero: String(t.numero).trim(), label: (t.label ?? null) || null })) : []; if (!list.length && constructeur.phone && constructeur.phone.trim()) { return [{ numero: constructeur.phone.trim(), label: null }]; } return list; }; export const constructeurPrimaryPhone = ( constructeur: ConstructeurPhoneSource, ): string | null => { const phones = constructeurPhones(constructeur); return phones.length ? phones[0]!.numero : null; }; export interface ConstructeurLinkEntry { linkId?: string; constructeurId: string; constructeur?: ConstructeurSummary | null; supplierReference: string | null; } export const constructeurIdsFromLinks = (links: ConstructeurLinkEntry[]): string[] => links.map(l => l.constructeurId).filter(Boolean); export const parseConstructeurLinksFromApi = ( apiLinks: any[], ): ConstructeurLinkEntry[] => { if (!Array.isArray(apiLinks)) return []; return apiLinks .filter(link => link && typeof link === 'object') .map(link => ({ linkId: link.id || (typeof link['@id'] === 'string' ? link['@id'].split('/').pop() : undefined), constructeurId: typeof link.constructeur === 'string' ? link.constructeur.split('/').pop()! : link.constructeur?.id || '', constructeur: typeof link.constructeur === 'object' ? link.constructeur : null, supplierReference: link.supplierReference ?? null, })); }; const isObject = (value: unknown): value is Record => Boolean(value) && typeof value === 'object' && !Array.isArray(value); const toStringId = (value: unknown): string | null => { if (typeof value !== 'string') { return null; } const trimmed = value.trim(); if (!trimmed) { return null; } if (trimmed.includes('/')) { const parts = trimmed.split('/').filter(Boolean); return parts.length ? (parts[parts.length - 1] ?? null) : null; } return trimmed; }; export const uniqueConstructeurIds = (...sources: unknown[]): string[] => { const ids = new Set(); const pushId = (value: unknown) => { const id = toStringId(value); if (id) { ids.add(id); } }; const explore = (value: unknown): void => { if (!value) { return; } if (Array.isArray(value)) { value.forEach(explore); return; } if (typeof value === 'string') { pushId(value); return; } if (isObject(value)) { if (Array.isArray(value.constructeurIds)) { value.constructeurIds.forEach(pushId); } if (value.constructeurId) { pushId(value.constructeurId); } if (Array.isArray(value.constructeurs)) { value.constructeurs.forEach(explore); } if (value.constructeur) { explore(value.constructeur); } // Extract ID from constructeur-like objects, but skip component/piece/product entities if (typeof value.id === 'string' && !value.typeComposant && !value.typePiece && !value.typeProduct) { pushId(value.id); } return; } }; sources.forEach(explore); return Array.from(ids); }; export const resolveConstructeurs = ( ids: string[], ...candidatePools: Array ): ConstructeurSummary[] => { if (!Array.isArray(ids) || ids.length === 0) { return []; } const index = new Map(); const register = (pool?: ConstructeurSummary[] | null) => { if (!Array.isArray(pool)) { return; } pool.forEach((entry) => { if (entry && typeof entry === 'object' && typeof entry.id === 'string') { index.set(entry.id, entry); } }); }; candidatePools.forEach(register); return ids .map((id) => index.get(id)) .filter((item): item is ConstructeurSummary => Boolean(item)) .map((item) => ({ ...item })); }; export const formatConstructeurContact = ( constructeur?: ConstructeurSummary | null, ): string => { if (!constructeur) { return ''; } const primary = constructeurPrimaryPhone(constructeur); const phone = formatPhone(primary) || primary || null; return [constructeur.email, phone].filter(Boolean).join(' • '); };