import type { UnifiedMatchResult, VerifiedPortfolioResult, ExternalMarketResult, FutureAvailabilityResult, } from '../../domain/unifiedResult' import type { ScoreFactor } from '../../domain/match' import type { MatchCardViewModel, MatchCardAction, MatchCardReason, } from '../../components/match-card/MatchCardViewModel' import { getCityIntelligence } from '../../lib/locationIntelligence' const HARD_CRITERIA = new Set(['area', 'location', 'budget', 'timing']) function buildReasons(positiveFactors: ScoreFactor[]): MatchCardReason[] { const reasons: MatchCardReason[] = [] const hardFact = positiveFactors.find(f => HARD_CRITERIA.has(f.criterion)) const softFact = positiveFactors.find(f => !HARD_CRITERIA.has(f.criterion)) if (hardFact) { reasons.push({ type: 'HARD_FACT', label: capitalize(hardFact.criterion), explanation: hardFact.explanation, score: hardFact.score, }) } if (softFact) { reasons.push({ type: 'SOFT_FACTOR', label: capitalize(softFact.criterion), explanation: softFact.explanation, score: softFact.score, }) } return reasons } function capitalize(s: string): string { return s.charAt(0).toUpperCase() + s.slice(1) } export function buildMatchCardViewModel( result: UnifiedMatchResult, actions: MatchCardAction[], ): MatchCardViewModel { const { match, matchScore, resultType } = result const isFuture = resultType === 'FUTURE_AVAILABILITY' const property = !isFuture ? (result as VerifiedPortfolioResult | ExternalMarketResult).property : undefined const signal = isFuture ? (result as FutureAvailabilityResult).signal : undefined const city = property?.location?.city const district = property?.location?.district const locationLabel = city ? `${city}${district ? `, ${district}` : ''}` : signal?.locationHint ?? '–' const availabilityLabel = property?.availabilityDate ?? (signal?.timeHorizonMonths ? `~${signal.timeHorizonMonths} Monate` : undefined) const sourceLabel = property?.sourceLabel ?? property?.sourceMeta?.sourceLabel ?? property?.sourceMeta?.sourceType const externalUrl = property?.sourceUrl ?? property?.sourceMeta?.sourceUrl const reasons = buildReasons(match.positiveFactors) const cityIntel = city ? getCityIntelligence(city) : null const taxCalculatorUrl = cityIntel?.taxCalculatorUrl const dataQualityScore = property?.dataQuality?.score ?? signal?.confidenceScore ?? 0.5 return { id: result.matchId, title: property?.title ?? signal?.companyName ?? signal?.locationHint ?? '–', resultType, assetType: property?.assetType, matchScore, confidenceScore: match.confidenceLevel, dataQualityScore, locationLabel, availabilityLabel, sourceLabel, externalUrl, reasons, tradeoffs: match.tradeoffs ?? [], risks: match.risks ?? [], missingData: match.missingData ?? [], actions, disclaimer: isFuture ? (signal?.disclaimer ?? 'Probabilistisches Signal – kein bestätigtes Objekt') : undefined, explainabilitySummary: match.explainabilitySummary, taxCalculatorUrl, isReviewRequired: match.status === 'PENDING_REVIEW', isStaleData: false, } }