import type { Property } from '../../domain/property'
import type { MustHaveResult } from '../../domain/match'

// ── Penalty per failed CERTAIN criterion (applied to totalScore) ──────────────
export const MUST_HAVE_PENALTY_PER_MISS = 8
export const MUST_HAVE_MAX_PENALTY = 24

interface KeywordRule {
  keywords: string[]
  check: (p: Property) => boolean | null   // null = data not available
  explanation: (p: Property, passed: boolean) => string
}

function parking(p: Property): number {
  return p.hardFacts?.parking ?? p.softFactors?.parkingSpots ?? 0
}

const RULES: KeywordRule[] = [
  {
    keywords: ['schaufenster', 'shopfenster', 'shopfront', 'ladenlokal', 'vitrine'],
    check: (p) => p.hardFacts?.hasStorefront ?? null,
    explanation: (p, ok) =>
      p.hardFacts?.hasStorefront === undefined
        ? 'Keine Daten zum Schaufenster verfügbar'
        : ok ? 'Schaufenster / Shopfront bestätigt' : 'Kein Schaufenster vorhanden',
  },
  {
    keywords: ['erdgeschoss', 'parterre', 'ground floor', 'eg ', 'eg,', '(eg)'],
    check: (p) => {
      const floor = p.hardFacts?.floor ?? p.floorLevel
      if (floor === undefined) return null
      return floor === 0
    },
    explanation: (p, ok) => {
      const floor = p.hardFacts?.floor ?? p.floorLevel
      if (floor === undefined) return 'Stockwerk nicht bekannt'
      return ok ? `Erdgeschoss bestätigt (Etage ${floor})` : `Nicht Erdgeschoss (Etage ${floor})`
    },
  },
  {
    keywords: ['klimaanlage', 'air conditioning', 'aircondition', 'klima ', 'kühlung', 'hvac', 'klimatisierung', 'klimatisier'],
    check: (p) => p.hardFacts?.hasAirConditioning ?? null,
    explanation: (p, ok) =>
      p.hardFacts?.hasAirConditioning === undefined
        ? 'Klimaanlage nicht dokumentiert'
        : ok ? 'Klimaanlage vorhanden' : 'Keine Klimaanlage vorhanden',
  },
  {
    keywords: ['laderampe', 'loading dock', 'rampe', 'verladerampe', 'tor'],
    check: (p) => {
      const docks = p.hardFacts?.loadingDocksCount
      if (docks === undefined) return null
      return docks > 0
    },
    explanation: (p, ok) => {
      const docks = p.hardFacts?.loadingDocksCount
      if (docks === undefined) return 'Laderampe / Tor nicht dokumentiert'
      return ok ? `${docks} Laderampe(n) vorhanden` : 'Keine Laderampe vorhanden'
    },
  },
  {
    keywords: ['parkplatz', 'parkplätze', 'parking', 'stellplatz', 'stellplätze', 'autoabstellplatz'],
    check: (p) => {
      const count = parking(p)
      return count > 0
    },
    explanation: (p, ok) => {
      const count = parking(p)
      if (count === 0) return 'Kein Parkplatz vorhanden oder keine Daten'
      return ok ? `${count} Parkplatz/Parkplätze vorhanden` : 'Kein Parkplatz'
    },
  },
  {
    keywords: ['barrierefrei', 'rollstuhl', 'handicap', 'behindertengerecht', 'iv-gerecht'],
    check: (p) => p.hardFacts?.isBarrierFree ?? null,
    explanation: (p, ok) =>
      p.hardFacts?.isBarrierFree === undefined
        ? 'Barrierefreiheit nicht dokumentiert'
        : ok ? 'Barrierefrei bestätigt' : 'Nicht barrierefrei',
  },
  {
    keywords: ['serverraum', 'rechenzentrum', 'server room', 'datacenter', 'it-raum'],
    check: (p) => p.hardFacts?.hasServerRoom ?? null,
    explanation: (p, ok) =>
      p.hardFacts?.hasServerRoom === undefined
        ? 'Serverraum nicht dokumentiert'
        : ok ? 'Serverraum vorhanden' : 'Kein Serverraum',
  },
  {
    keywords: ['langfristig', 'festvertrag', 'langzeitmiete', '10 jahre', '10-jahres', 'langfristiger vertrag'],
    check: (p) => {
      const dur = p.contractDurationMonths
      if (dur === undefined) return null
      return dur >= 120
    },
    explanation: (p, ok) => {
      const dur = p.contractDurationMonths
      if (dur === undefined) return 'Vertragsdauer nicht bekannt'
      return ok
        ? `Langfristige Vermietung möglich (${Math.round(dur / 12)} Jahre)`
        : `Nur bis ${Math.round(dur / 12)} Jahre — langfristiger Vertrag evtl. nicht möglich`
    },
  },
  {
    keywords: ['tageslicht', 'fensterfront', 'natural light', 'natürliches licht', 'aussenfenster'],
    check: (_p) => null, // no structured field yet — always UNKNOWN
    explanation: (_p, _ok) => 'Tageslicht / Fensterfront nicht strukturiert erfasst',
  },
  {
    keywords: ['ausbaugrad', 'ausbaustandard', 'vollausbau', 'modern ausgebaut', 'plug and play', 'bezugsfertig', 'gehoben ausgebaut'],
    check: (p) => {
      const fitOut = p.hardFacts?.fitOut
      if (!fitOut) return null
      return fitOut === 'FULL' || fitOut === 'PREMIUM'
    },
    explanation: (p, ok) => {
      const fitOut = p.hardFacts?.fitOut
      if (!fitOut) return 'Ausbaustandard nicht dokumentiert'
      const LABELS: Record<string, string> = { SHELL: 'Rohbau', BASIC: 'Basisausbau', FULL: 'Vollausbau', PREMIUM: 'Premiumausbau' }
      return ok
        ? `${LABELS[fitOut] ?? fitOut} — moderner Ausbaustandard erfüllt`
        : `${LABELS[fitOut] ?? fitOut} — nicht auf modernem Ausbauniveau`
    },
  },
]

// ── Number extraction helpers ──────────────────────────────────────────────────

function extractNumber(text: string): number | null {
  const m = text.match(/(\d+)/)
  return m ? parseInt(m[1], 10) : null
}

function extractMinuteLimit(text: string): number | null {
  const m = text.match(/(?:unter|<|≤|max\.?)\s*(\d+)/) ?? text.match(/(\d+)\s*min/i)
  return m ? parseInt(m[1], 10) : null
}

function isParkingKeyword(text: string): boolean {
  return RULES[4].keywords.some(kw => text.toLowerCase().includes(kw))
}

function isOevKeyword(text: string): boolean {
  return text.includes('öv-anbindung') || text.includes('öv anbindung') ||
    text.includes('öv-anschluss') || text.includes('öffentlicher verkehr') ||
    (text.includes('öv') && (text.includes('min') || text.includes('anbindung')))
}

function isMindestflaecheKeyword(text: string): boolean {
  return text.includes('mindestfläche') || text.includes('mindestnutzfläche') || text.includes('mindest-fläche')
}

// ── Main scorer ───────────────────────────────────────────────────────────────

export function scoreMustHaves(
  criteria: string[],
  property: Property,
): {
  results: MustHaveResult[]
  passedCount: number
  totalCount: number
  scoreImpact: number
} {
  if (criteria.length === 0) {
    return { results: [], passedCount: 0, totalCount: 0, scoreImpact: 0 }
  }

  const results: MustHaveResult[] = criteria.map((raw) => {
    const lower = raw.toLowerCase()

    // Special case: ÖV-Anbindung with minute limit ("< 5 Min", "unter 10 Min")
    if (isOevKeyword(lower)) {
      const minutes = property.softFactors?.publicTransportMinutes
      if (minutes === undefined) {
        return { criterion: raw, passed: false, confidence: 'UNKNOWN' as const, explanation: 'ÖV-Fahrzeit nicht dokumentiert' }
      }
      const limit = extractMinuteLimit(lower) ?? 10
      const passed = minutes <= limit
      return {
        criterion: raw,
        passed,
        confidence: 'CERTAIN' as const,
        explanation: passed
          ? `${minutes} Min. zu Fuss zum ÖV — Limit ${limit} Min. erfüllt`
          : `${minutes} Min. zu Fuss — überschreitet ${limit}-Min.-Limit`,
      }
    }

    // Special case: Mindestfläche with m² threshold ("Mindestfläche 600m²")
    if (isMindestflaecheKeyword(lower)) {
      const required = extractNumber(lower)
      if (required === null) {
        return { criterion: raw, passed: false, confidence: 'UNKNOWN' as const, explanation: 'Mindestfläche konnte nicht ausgelesen werden' }
      }
      const passed = property.areaSqm >= required
      return {
        criterion: raw,
        passed,
        confidence: 'CERTAIN' as const,
        explanation: passed
          ? `${property.areaSqm.toLocaleString('de-CH')} m² deckt Mindestfläche ${required} m² ab`
          : `${property.areaSqm.toLocaleString('de-CH')} m² liegt unter Mindestfläche ${required} m²`,
      }
    }

    // Special case: parking with minimum count ("mind. 5 parkplätze")
    if (isParkingKeyword(lower)) {
      const required = extractNumber(lower)
      const available = parking(property)
      if (required !== null) {
        const passed = available >= required
        return {
          criterion: raw,
          passed,
          confidence: 'CERTAIN' as const,
          explanation: passed
            ? `${available} Parkplätze vorhanden (mind. ${required} verlangt)`
            : `Nur ${available} Parkplätze (mind. ${required} verlangt)`,
        }
      }
      // No number: just check if any parking available
      const hasParking = available > 0
      return {
        criterion: raw,
        passed: hasParking,
        confidence: available === 0 ? 'UNKNOWN' as const : 'CERTAIN' as const,
        explanation: hasParking ? `${available} Parkplatz/Parkplätze vorhanden` : 'Keine Parkplätze dokumentiert',
      }
    }

    for (const rule of RULES) {
      if (rule.keywords.some(kw => lower.includes(kw))) {
        const result = rule.check(property)
        if (result === null) {
          return {
            criterion: raw,
            passed: false,
            confidence: 'UNKNOWN' as const,
            explanation: rule.explanation(property, false),
          }
        }
        return {
          criterion: raw,
          passed: result,
          confidence: 'CERTAIN' as const,
          explanation: rule.explanation(property, result),
        }
      }
    }

    // No keyword matched
    return {
      criterion: raw,
      passed: false,
      confidence: 'UNKNOWN' as const,
      explanation: 'Kriterium konnte nicht automatisch geprüft werden',
    }
  })

  const certain = results.filter(r => r.confidence === 'CERTAIN')
  const passedCount = results.filter(r => r.passed && r.confidence !== 'UNKNOWN').length
  const failedCertain = certain.filter(r => !r.passed).length
  const scoreImpact = -Math.min(MUST_HAVE_MAX_PENALTY, failedCertain * MUST_HAVE_PENALTY_PER_MISS)

  return {
    results,
    passedCount,
    totalCount: certain.length,
    scoreImpact,
  }
}
