import { useMemo } from 'react' import type { Property, PropertyUnit } from '../domain/property' import type { FutureSignal } from '../domain/futureSignal' import { SignalType, RiskLevel, ResultType } from '../domain/enums' // Matches the mock date used throughout the prototype (currentDate context: 2026-05-20) const MOCK_TODAY = new Date('2026-05-20') export function useSchattenmarktSignals(properties: Property[]): FutureSignal[] { return useMemo(() => { const signals: FutureSignal[] = [] for (const p of properties) { if (p.resultType !== ResultType.VERIFIED_PORTFOLIO) continue const rel = p.schattenmarktRelease if (!rel?.enabled) continue // Unit-level: generate one signal per released unit that has schattenmarktRelease.enabled const releasedUnits = (p.units ?? []).filter(u => u.schattenmarktRelease?.enabled) if (releasedUnits.length > 0) { for (const unit of releasedUnits) { const availableFrom = unit.schattenmarktRelease?.availableFrom ?? unit.leaseEndDate ?? p.leaseEndDate if (!availableFrom) continue const triggerDate = getTriggerDate(availableFrom, rel.leadTimeMonths ?? 0) if (MOCK_TODAY < triggerDate) continue signals.push(buildUnitSignal(p, unit, availableFrom)) } } else { // Backward compat: property-level signal (no explicit unit releases defined) const triggerDate = getEarliestTriggerDate(p, rel.leadTimeMonths ?? 0) if (!triggerDate || MOCK_TODAY < triggerDate) continue signals.push(buildPropertySignal(p)) } } return signals }, [properties]) } function getTriggerDate(availableFrom: string, leadTimeMonths: number): Date { const d = new Date(availableFrom) d.setMonth(d.getMonth() - leadTimeMonths) return d } function getEarliestTriggerDate(p: Property, leadTimeMonths: number): Date | null { const candidates: Date[] = [] if (p.leaseEndDate) { const d = new Date(p.leaseEndDate) d.setMonth(d.getMonth() - leadTimeMonths) candidates.push(d) } if (p.breakoutOption && p.breakoutOptionDate) { const d = new Date(p.breakoutOptionDate) d.setMonth(d.getMonth() - leadTimeMonths) candidates.push(d) } return candidates.length ? candidates.reduce((a, b) => (a < b ? a : b)) : null } function buildUnitSignal(p: Property, unit: PropertyUnit, availableFrom: string): FutureSignal { const targetDate = new Date(availableFrom) const monthsUntil = Math.max(1, Math.round( (targetDate.getTime() - MOCK_TODAY.getTime()) / (1000 * 60 * 60 * 24 * 30), )) const locationLabel = `${p.location.city}${p.location.district ? `, ${p.location.district}` : ''}` const monthName = targetDate.toLocaleDateString('de-CH', { month: 'long', year: 'numeric' }) const floorLabel = unit.floorLevel === 0 ? 'EG' : unit.floorLevel < 0 ? `UG ${Math.abs(unit.floorLevel)}` : `${unit.floorLevel}.OG` const unitDesc = unit.unitLabel ? `${floorLabel} · ${unit.unitLabel}` : floorLabel return { id: `schattenmarkt-${p.id}-${unit.id}`, signalType: SignalType.LEASE_EXPIRY, propertyId: p.id, unitId: unit.id, title: `${p.title} · ${unitDesc} — frei ab ${monthName}`, locationHint: locationLabel, areaSqmEstimate: unit.areaSqm, probability: 0.92, confidenceScore: 0.92, timeHorizonMonths: monthsUntil, source: { type: 'LEASE_CONTRACT', credibility: 'HIGH' }, sensitivityLevel: 'INTERNAL', disclaimer: 'Verwaltung hat diese Einheit für Pre-Market-Sichtbarkeit freigegeben. Vertragsende aus internem ERP bestätigt — höchste Signalqualität.', riskLevel: RiskLevel.LOW, relevanceScore: 0.92, isVerified: true, organizationId: p.organizationId, createdAt: MOCK_TODAY.toISOString(), updatedAt: MOCK_TODAY.toISOString(), aiSummary: `Vertrag der ${unit.currentTenant ?? p.currentTenant ?? 'aktuellen Mietpartei'} läuft in ${monthsUntil} Monaten aus (${monthName}). Einheit: ${unit.areaSqm.toLocaleString('de-CH')} m² · ${unitDesc} · ${locationLabel}. Die Verwaltung hat diese Einheit explizit für den Markt freigegeben — vertraglich bestätigt.`, marketIndicators: [ `Vertragsende ${monthName} aus Verwaltungssystem bestätigt`, `Einheit ${unitDesc} · ${unit.areaSqm.toLocaleString('de-CH')} m² · ${locationLabel}`, `Pre-Market-Freigabe durch Verwaltung erteilt`, ], confirmedFacts: [ `Vertragsende ${monthName} aus ERP bestätigt`, `${unit.areaSqm.toLocaleString('de-CH')} m² · ${unitDesc} — bestätigt`, `Standort ${locationLabel} — bestätigt`, ], unconfirmedFacts: [ 'Ob Nachmieter bereits bekannt', 'Ob Umbaumassnahmen geplant', ], } } function buildPropertySignal(p: Property): FutureSignal { const targetDate = p.breakoutOption && p.breakoutOptionDate ? new Date(p.breakoutOptionDate) : p.leaseEndDate ? new Date(p.leaseEndDate) : new Date() const monthsUntil = Math.max(1, Math.round( (targetDate.getTime() - MOCK_TODAY.getTime()) / (1000 * 60 * 60 * 24 * 30), )) const locationLabel = `${p.location.city}${p.location.district ? `, ${p.location.district}` : ''}` const monthName = targetDate.toLocaleDateString('de-CH', { month: 'long', year: 'numeric' }) return { id: `schattenmarkt-${p.id}`, signalType: SignalType.LEASE_EXPIRY, propertyId: p.id, title: `${p.title} — frei ab ${monthName}`, locationHint: locationLabel, areaSqmEstimate: p.areaSqm, probability: 0.92, confidenceScore: 0.92, timeHorizonMonths: monthsUntil, source: { type: 'LEASE_CONTRACT', credibility: 'HIGH' }, sensitivityLevel: 'INTERNAL', disclaimer: 'Verwaltung hat diese Fläche für Pre-Market-Sichtbarkeit freigegeben. Vertragsende aus internem ERP bestätigt — höchste Signalqualität.', riskLevel: RiskLevel.LOW, relevanceScore: 0.92, isVerified: true, organizationId: p.organizationId, createdAt: MOCK_TODAY.toISOString(), updatedAt: MOCK_TODAY.toISOString(), aiSummary: `Vertrag der ${p.currentTenant ?? 'aktuellen Mietpartei'} läuft in ${monthsUntil} Monaten aus (${monthName}). Fläche: ${p.areaSqm.toLocaleString('de-CH')} m² · ${locationLabel}. Die Verwaltung hat dieses Objekt explizit für den Markt freigegeben — vertraglich bestätigt, keine Schätzung.`, marketIndicators: [ `Vertragsende ${monthName} aus Verwaltungssystem bestätigt`, `Fläche ${p.areaSqm.toLocaleString('de-CH')} m² — ${locationLabel}`, `Pre-Market-Freigabe durch Verwaltung erteilt`, ], confirmedFacts: [ `Vertragsende ${monthName} aus ERP bestätigt`, `Fläche ${p.areaSqm.toLocaleString('de-CH')} m² — bestätigt`, `Standort ${locationLabel} — bestätigt`, ], unconfirmedFacts: [ 'Ob Nachmieter bereits bekannt', 'Ob Umbaumassnahmen geplant', ], } }