import type { INeedProvider, NeedFilters } from './INeedProvider'
import type { Need, CreateNeedInput, UpdateNeedInput } from '../domain/need'
import { mockNeeds } from '../mock-data/needs'
import { matchStore } from './MockupMatchProvider'
import { propertyStore } from './MockupPropertyProvider'
import { MatchStrength, MatchStatus, RiskLevel } from '../domain/enums'
import type { Match } from '../domain/match'

const store: Need[] = [...mockNeeds]

// ── Location scoring ───────────────────────────────────────────────────────────

const CANTON_MAP: Record<string, string> = {
  zürich: 'zh', zug: 'zg', winterthur: 'zh', uster: 'zh', bülach: 'zh', oerlikon: 'zh',
  bern: 'be', biel: 'be', thun: 'be', köniz: 'be',
  basel: 'bs', muttenz: 'bl', pratteln: 'bl', reinach: 'bl', allschwil: 'bl', binningen: 'bl',
  genf: 'ge', genève: 'ge', carouge: 'ge', lancy: 'ge',
  'st. gallen': 'sg', 'st.gallen': 'sg', rapperswil: 'sg',
}

function locationScore(propCity: string, preferredLocations: string[]): number {
  const pc = propCity.toLowerCase()
  for (const pref of preferredLocations) {
    const p = pref.toLowerCase()
    if (pc.includes(p) || p.includes(pc)) return 1.0
  }
  // Same canton check
  const propCanton = CANTON_MAP[pc]
  if (propCanton) {
    for (const pref of preferredLocations) {
      const prefCanton = CANTON_MAP[pref.toLowerCase()]
      if (prefCanton && prefCanton === propCanton) return 0.55
    }
  }
  return 0.30
}

function computeScore(prop: { assetType: string; areaSqm: number; rentPricePerSqm: number; location: { city: string } }, need: Need): number | null {
  if (need.assetType && prop.assetType !== need.assetType) return null

  const locScore = locationScore(prop.location.city, need.preferredLocations ?? [])

  // Location dominates: same city → 50-90 base, different → 25-45
  let score = locScore >= 0.9 ? 65 : locScore >= 0.5 ? 42 : 28

  // Area overlap (+0-20)
  if (need.requiredArea && prop.areaSqm) {
    const { min, max } = need.requiredArea
    if (prop.areaSqm >= min && prop.areaSqm <= max) score += 20
    else if (prop.areaSqm >= min * 0.7 && prop.areaSqm <= max * 1.5) score += 10
    else if (prop.areaSqm < min * 0.5 || prop.areaSqm > max * 2) score -= 10
  }

  // Budget fit (+0-10)
  if (need.budgetRange?.maxPerSqm && prop.rentPricePerSqm) {
    if (prop.rentPricePerSqm <= need.budgetRange.maxPerSqm) score += 10
    else if (prop.rentPricePerSqm <= need.budgetRange.maxPerSqm * 1.2) score += 3
    else score -= 8
  }

  // Small jitter so results look natural
  score += Math.floor(Math.random() * 6) - 2

  return Math.min(97, Math.max(22, score))
}

function strengthFromScore(s: number): string {
  if (s >= 75) return MatchStrength.STRONG
  if (s >= 55) return MatchStrength.MODERATE
  return MatchStrength.WEAK
}

function generateSyntheticMatches(need: Need) {
  const now = new Date().toISOString()

  for (const prop of propertyStore) {
    const score = computeScore(prop, need)
    if (score === null || score < 25) continue

    const locS = locationScore(prop.location.city, need.preferredLocations ?? [])
    const isGoodLoc = locS >= 0.9

    const match: Match = {
      id: crypto.randomUUID(),
      propertyId: prop.id,
      needId: need.id,
      resultId: prop.id,
      resultType: prop.resultType ?? 'VERIFIED_PORTFOLIO',
      matchScore: score,
      matchStrength: strengthFromScore(score) as typeof MatchStrength[keyof typeof MatchStrength],
      status: score >= 75 ? MatchStatus.PENDING_REVIEW : MatchStatus.PENDING_REVIEW,
      scoreBreakdown: {
        hardMatchScore: score + 5,
        softFactorScore: score - 5,
        confidenceModifier: isGoodLoc ? 0.96 : 0.82,
        dataQualityModifier: 0.92,
        totalScore: score,
      },
      positiveFactors: isGoodLoc
        ? [{ criterion: 'Standort', weight: 0.25, score: 92, contribution: 23, explanation: `${prop.location.city} – bevorzugter Standort` }]
        : [{ criterion: 'Fläche', weight: 0.25, score: 70, contribution: 17.5, explanation: `${prop.areaSqm} m² verfügbar` }],
      negativeFactors: !isGoodLoc
        ? [{ criterion: 'Standort', weight: 0.25, score: 35, contribution: 8.75, explanation: `${prop.location.city} liegt außerhalb der bevorzugten Region` }]
        : [],
      tradeoffs: !isGoodLoc
        ? [{ criterion: 'Standort', concern: `${prop.location.city} ist nicht im Präferenzgebiet`, severity: 'MEDIUM' as const }]
        : [],
      explainabilitySummary: isGoodLoc
        ? `${prop.location.city} trifft den Standortwunsch. Objekt entspricht den Kernkriterien.`
        : `Abweichender Standort (${prop.location.city}). Nur bei Engpass im Zielgebiet empfohlen.`,
      confidenceLevel: isGoodLoc ? 0.88 : 0.60,
      riskLevel: isGoodLoc ? RiskLevel.LOW : RiskLevel.MEDIUM,
      uncertaintyIndicators: isGoodLoc ? [] : ['Standort außerhalb Präferenz'],
      organizationId: 'org-wincasa',
      createdAt: now,
      updatedAt: now,
    }

    matchStore.push(match)
  }
}

// ── Provider ───────────────────────────────────────────────────────────────────

export const MockupNeedProvider: INeedProvider = {
  async getAll(filters?: NeedFilters) {
    let results = [...store]
    if (filters?.assetType) results = results.filter(n => n.assetType === filters.assetType)
    if (filters?.organizationId) results = results.filter(n => n.organizationId === filters.organizationId)
    if (filters?.companyName) results = results.filter(n => n.companyName.toLowerCase().includes(filters.companyName!.toLowerCase()))
    return results
  },
  async getById(id) {
    return store.find(n => n.id === id) ?? null
  },
  async create(data: CreateNeedInput) {
    const next: Need = { id: crypto.randomUUID(), ...data, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }
    store.push(next)
    generateSyntheticMatches(next)
    return next
  },
  async update(id, data: UpdateNeedInput) {
    const idx = store.findIndex(n => n.id === id)
    store[idx] = { ...store[idx], ...data, updatedAt: new Date().toISOString() }
    return store[idx]
  },
  async remove(id) {
    const idx = store.findIndex(n => n.id === id)
    store.splice(idx, 1)
  },
}
