import type { UnifiedMatchResult } from '../../../domain/unifiedResult' import type { ComparisonSummary } from '../IAIService' export function buildComparisonSummary(items: UnifiedMatchResult[]): ComparisonSummary { const getTitle = (item: UnifiedMatchResult) => item.resultType !== 'FUTURE_AVAILABILITY' ? (item as any).property?.title ?? `Match ${item.matchScore}` : (item as any).signal?.companyName ?? 'Zukunftssignal' if (items.length === 0) { return { strongestOption: { matchId: '', label: '–', reason: 'Keine Ergebnisse' }, bestValue: null, highestConfidence: { matchId: '', label: '–', confidenceLevel: 0 }, biggestTradeoffs: [], missingDataWarnings: [], recommendedNextStep: 'Suchergebnisse überprüfen', overallAssessment: 'Keine Ergebnisse für die Analyse verfügbar.', perPropertyAssessment: [], recommendation: 'Suchergebnisse überprüfen und erneut versuchen.', } } const strongest = items.reduce((a, b) => a.matchScore > b.matchScore ? a : b) const propertyItems = items.filter(i => i.resultType !== 'FUTURE_AVAILABILITY') const bestValue = propertyItems.length > 0 ? propertyItems.reduce((a, b) => ((a as any).property?.rentPricePerSqm ?? Infinity) <= ((b as any).property?.rentPricePerSqm ?? Infinity) ? a : b ) : null const highestConf = items.reduce((a, b) => a.match.confidenceLevel >= b.match.confidenceLevel ? a : b ) const tradeoffs = items .flatMap(i => i.match.tradeoffs?.slice(0, 1).map(t => `${getTitle(i)}: ${t.concern}`) ?? []) .slice(0, 3) const missingWarnings = items .filter(i => (i.match.missingData?.filter(m => m.importance === 'CRITICAL').length ?? 0) > 0) .map(i => `${getTitle(i)}: fehlende Pflichtfelder`) const topNextAction = strongest.match.nextBestActions?.[0]?.label ?? 'Objekt besichtigen oder Details prüfen' // Overall assessment const labels = items.map(getTitle) const scoreLeader = getTitle(strongest) const priceLeader = bestValue ? getTitle(bestValue) : null let overallAssessment: string if (items.length === 1) { overallAssessment = `${labels[0]} erfüllt die Kernkriterien mit einem Match Score von ${strongest.matchScore}/100. Eine Vergleichsbasis fehlt — weitere Optionen hinzufügen für eine fundierte Entscheidung.` } else if (priceLeader && priceLeader !== scoreLeader) { overallAssessment = `Beide Optionen erfüllen Standort und Fläche gut. ${scoreLeader} führt beim Match Score und Prestige, ${priceLeader} beim Preis-Leistungs-Verhältnis.` } else { overallAssessment = `${scoreLeader} dominiert in den meisten Kriterien mit dem höchsten Match Score (${strongest.matchScore}/100). Die Optionen unterscheiden sich hauptsächlich in Lage und Ausstattung.` } // Per-property assessment const deriveBestFor = (item: UnifiedMatchResult): string => { const assetType = (item as any).property?.assetType ?? '' const score = item.matchScore const hasPosPrestige = item.match.positiveFactors.some(f => f.criterion.toLowerCase().includes('prestige') || f.criterion.toLowerCase().includes('location') ) const hasLowPrice = bestValue?.matchId === item.matchId if (hasPosPrestige && score >= 80) return 'Repräsentationsbedarf mit Prestige-Anforderungen' if (hasLowPrice) return 'Kostenoptimierte Wachstumsphase' if (assetType === 'LOGISTICS' || assetType === 'PRODUCTION') return 'Operative Effizienz und Flächenflexibilität' if (assetType === 'RETAIL') return 'Hohe Kundenfrequenz und Sichtbarkeit' if (score >= 80) return 'Anspruchsvolle Anforderungen mit hoher Matchqualität' return 'Ausgewogenes Preis-Leistungs-Profil' } const perPropertyAssessment = items.map(item => { const topStrengths = item.match.positiveFactors .slice(0, 2) .map(f => f.explanation) const topWeaknesses = item.match.negativeFactors.length > 0 ? item.match.negativeFactors.slice(0, 2).map(f => f.explanation) : ['Keine kritischen Schwächen identifiziert'] const keyRisk = item.match.risks?.[0]?.description ?? null return { matchId: item.matchId, label: getTitle(item), strengths: topStrengths, weaknesses: topWeaknesses, bestFor: deriveBestFor(item), keyRisk, } }) // Recommendation const recommendation = items.length >= 2 ? `Besichtigung beider Objekte empfohlen — danach Entscheidung auf Basis Mietvertragslaufzeit und Ausbaustandard.` : `Besichtigung von ${getTitle(strongest)} empfohlen — anschliessend Vertragskonditionen und Laufzeit prüfen.` return { strongestOption: { matchId: strongest.matchId, label: getTitle(strongest), reason: `Höchster Match Score (${strongest.matchScore}/100)`, }, bestValue: bestValue ? { matchId: bestValue.matchId, label: getTitle(bestValue), reason: `Niedrigster Mietpreis (CHF ${(bestValue as any).property?.rentPricePerSqm ?? '–'}/m²)`, } : null, highestConfidence: { matchId: highestConf.matchId, label: getTitle(highestConf), confidenceLevel: highestConf.match.confidenceLevel, }, biggestTradeoffs: tradeoffs, missingDataWarnings: missingWarnings, recommendedNextStep: topNextAction, overallAssessment, perPropertyAssessment, recommendation, } }