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'
import { formatUnitTitle, formatMultiUnitFloors, getUnitAvailability } from '../../domain/unit'
import { calcFitOutInvestment } from '../../lib/fitOutUtils'
import { resolveUnitFacts } from '../../lib/unitFacts'
import { AvailabilityStatus } from '../../domain/enums'

const HARD_CRITERIA = new Set(['area', 'location', 'budget', 'timing'])

function buildReasons(positiveFactors: ScoreFactor[]): MatchCardReason[] {
  return positiveFactors.slice(0, 3).map(f => ({
    type: (HARD_CRITERIA.has(f.criterion) ? 'HARD_FACT' : 'SOFT_FACTOR') as MatchCardReason['type'],
    label: capitalize(f.criterion),
    explanation: f.explanation,
    score: f.score,
  }))
}

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
    : (result as FutureAvailabilityResult).property
  const signal = isFuture
    ? (result as FutureAvailabilityResult).signal
    : undefined
  const unit = isFuture
    ? (result as FutureAvailabilityResult).unit
    : (result as VerifiedPortfolioResult | ExternalMarketResult).unit

  const city = property?.location?.city
  const district = property?.location?.district
  const locationLabel = city
    ? `${city}${district ? `, ${district}` : ''}`
    : signal?.locationHint ?? '–'

  // Unit-first title: specific unit → floor range of all units → signal → property
  let cardTitle: string
  let propertySubtitle: string | undefined

  if (unit && property?.address) {
    cardTitle = formatUnitTitle(unit, property.address)
    propertySubtitle = property.title
  } else if (signal?.title) {
    cardTitle = signal.title
  } else if (property?.units && property.units.length > 0 && property.address) {
    const floorRange = formatMultiUnitFloors(property.units)
    cardTitle = `${floorRange} · ${property.address.street} ${property.address.houseNumber}`
    propertySubtitle = property.title
  } else {
    cardTitle = property?.title ?? signal?.companyName ?? signal?.locationHint ?? '–'
  }

  // Prefer unit-level availability (from Lease), fall back to property-level date, then signal
  const unitAvail = unit ? getUnitAvailability(unit) : null
  const availabilityLabel = (() => {
    if (unitAvail?.availableFrom) {
      return `ab ${new Date(unitAvail.availableFrom).toLocaleDateString('de-CH', { month: 'short', year: '2-digit' })}`
    }
    if (unitAvail?.status === AvailabilityStatus.AVAILABLE_NOW) return 'Sofort verfügbar'
    if (property?.availabilityDate) {
      return `ab ${new Date(property.availabilityDate).toLocaleDateString('de-CH', { month: 'short', year: '2-digit' })}`
    }
    if (signal?.timeHorizonMonths) return `~${signal.timeHorizonMonths} Monate`
    return 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: cardTitle,
    propertySubtitle,
    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,
    // Schattenmarkt signal fields
    signalSourceType: signal?.source?.type,
    signalSourceUrl: signal?.source?.url,
    signalSourceCredibility: signal?.source?.credibility,
    signalProbability: signal?.probability,
    signalMarketIndicator: signal?.marketIndicator,
    signalType: signal?.signalType,
    signalIsVerified: signal?.isVerified,
    aiSignalSummary: signal?.aiSummary,
    signalQuality: (() => {
      if (!signal) return undefined
      if (signal.isVerified || signal.probability >= 0.70) return 'HIGH'
      if (signal.probability >= 0.50) return 'MEDIUM'
      return 'LOW'
    })(),
    signalIsControlled: signal?.signalType === 'LEASE_EXPIRY' && signal?.isVerified === true,
    signalMarketIndicators: signal?.marketIndicators,
    signalStrategicInterpretation: signal?.strategicInterpretation,
    signalConfirmedFacts: signal?.confirmedFacts,
    signalUnconfirmedFacts: signal?.unconfirmedFacts,
    signalAreaSqmEstimate: signal?.areaSqmEstimate,
    areaSqm: unit?.areaSqm ?? property?.areaSqm ?? signal?.areaSqmEstimate,
    rentPerSqm: property?.rentPricePerSqm,
    propertyId: property?.id ?? signal?.propertyId,
    unitId: match.unitId ?? unit?.id ?? signal?.unitId,
    preMarketUnit: unit,
    preMarketAllUnits: property?.units,
    fitOutLabel: (() => {
      // Einheit-Werte haben Vorrang vor Objekt-Werten (Pre-Market / Mehr-Einheiten)
      if (!property) return undefined
      const { fitOut, mabPerSqm } = resolveUnitFacts(property, unit)
      if (!fitOut) return undefined
      const LABELS: Record<string, string> = { SHELL: 'Rohbau', BASIC: 'Basisausbau', FULL: 'Vollausbau', PREMIUM: 'Premiumausbau' }
      if (fitOut === 'FULL' || fitOut === 'PREMIUM') return `${LABELS[fitOut]} — bezugsfertig`
      if (mabPerSqm) return `${LABELS[fitOut]} + CHF ${mabPerSqm} MAB`
      return LABELS[fitOut] ?? fitOut
    })(),
    fitOutViable: (() => {
      if (!property) return undefined
      const { fitOut, mabPerSqm } = resolveUnitFacts(property, unit)
      if (!fitOut) return undefined
      if (fitOut === 'FULL' || fitOut === 'PREMIUM') return true
      if (fitOut === 'BASIC' && mabPerSqm >= 150) return true
      if (fitOut === 'SHELL' && mabPerSqm >= 350) return true
      return undefined
    })(),
    fitOutInvestment: (() => {
      if (!property) return undefined
      const { fitOut, mabPerSqm } = resolveUnitFacts(property, unit)
      if (!fitOut || fitOut === 'FULL' || fitOut === 'PREMIUM') return undefined
      const area = unit?.areaSqm ?? property.areaSqm ?? 0
      return calcFitOutInvestment(fitOut, area, mabPerSqm, 0) ?? undefined
    })(),
    isDivisible: property?.units ? property.units.length > 1 : false,
    minDivisibleUnitSqm: (() => {
      if (!property?.units || property.units.length <= 1) return undefined
      const flexible = property.units.filter(u => u.isFlexible && u.minLettableSqm)
      if (flexible.length > 0) return Math.min(...flexible.map(u => u.minLettableSqm!))
      return Math.min(...property.units.map(u => u.areaSqm))
    })(),
    scoreBreakdown: {
      hardMatchScore: match.scoreBreakdown.hardMatchScore,
      softFactorScore: match.scoreBreakdown.softFactorScore,
      totalScore: match.scoreBreakdown.totalScore,
    },
    allFactors: match.allFactors,
  }
}
