/**
 * Feature/Symbol-Repair Skript
 *
 * Problem: Features (Zeichnungen) speichern Symbol-Referenzen als iconId in
 * properties JSONB. Nach dem Icon-Verlust zeigen diese auf gelöschte UUIDs.
 *
 * Dieses Skript versucht:
 * 1. Alle symbol-Features zu scannen
 * 2. Zu prüfen, ob die referenzierte iconId noch existiert
 * 3. Falls nicht: via migratedFromIconId oder Dateinamen-Matching zu reparieren
 *
 * Ausführung:
 *   Dry-Run (nur Analyse, keine Änderungen):
 *     node prisma/repair-features.js --dry-run
 *
 *   Apply (mit Backup und Reparatur):
 *     node prisma/repair-features.js --apply
 *
 * SAFETY:
 *   - In Production (NODE_ENV=production) nur mit --apply möglich
 *   - Vor Apply wird automatisch ein JSON-Backup erstellt
 *   - Keine Features werden gelöscht
 *   - Keine Projekte oder Tenant-Daten werden verändert
 */

const { PrismaClient } = require('@prisma/client')
const fs = require('fs')
const path = require('path')

const prisma = new PrismaClient()

const IS_DRY_RUN = process.argv.includes('--dry-run')
const IS_APPLY = process.argv.includes('--apply')
const IS_PROD = process.env.NODE_ENV === 'production'

// ─── Safety Guards ─────────────────────────────────────────────────────────

if (!IS_DRY_RUN && !IS_APPLY) {
  console.error('❌ Fehler: Bitte --dry-run oder --apply angeben')
  console.error('')
  console.error('  Analyse-Modus (keine Änderungen):')
  console.error('    node prisma/repair-features.js --dry-run')
  console.error('')
  console.error('  Reparatur-Modus (mit Backup):')
  console.error('    node prisma/repair-features.js --apply')
  process.exit(1)
}

if (IS_DRY_RUN && IS_APPLY) {
  console.error('❌ Fehler: --dry-run und --apply können nicht zusammen verwendet werden')
  process.exit(1)
}

if (IS_APPLY) {
  console.log('⚠️  REPAIR-MODUS (mit Änderungen)')
  if (IS_PROD) {
    console.log('   Production-Umgebung erkannt. Fortfahren in 3 Sekunden...')
    await new Promise(r => setTimeout(r, 3000))
  }
} else {
  console.log('🔍 DRY-RUN MODUS (keine Änderungen)')
}

// ─── Statistics ────────────────────────────────────────────────────────────

const stats = {
  totalFeatures: 0,
  validRefs: 0,
  brokenRefs: 0,
  repaired: 0,
  notRepairable: 0,
  details: [],
}

// ─── Main ──────────────────────────────────────────────────────────────────

async function repair() {
  console.log('\n🔧 Feature-Repair gestartet')
  console.log('────────────────────────────────────────')

  // ─── 1. Lade alle gültigen Icons für schnelle Lookup ───
  console.log('\n[1/5] Lade Icon-Lookup-Tabellen...')

  const allIcons = await prisma.iconAsset.findMany({
    select: { id: true, name: true, fileKey: true },
  })
  const iconById = new Map(allIcons.map(i => [i.id, i]))
  const iconByFileKey = new Map(allIcons.map(i => [i.fileKey, i]))

  // tenant_symbols mit migratedFromIconId
  const tenantSymbols = await prisma.tenantSymbol.findMany({
    select: { id: true, iconId: true, migratedFromIconId: true, customName: true },
  })
  const tsByMigratedId = new Map()
  for (const ts of tenantSymbols) {
    if (ts.migratedFromIconId) {
      tsByMigratedId.set(ts.migratedFromIconId, ts)
    }
  }

  console.log(`   ✅ ${allIcons.length} IconAssets geladen`)
  console.log(`   ✅ ${tenantSymbols.length} TenantSymbols geladen`)

  // ─── 2. Lade alle symbol-Features ───
  console.log('\n[2/5] Scanne Features...')

  const features = await prisma.feature.findMany({
    where: { type: 'symbol' },
    include: { project: { select: { id: true, title: true, tenantId: true } } },
    orderBy: { createdAt: 'asc' },
  })

  stats.totalFeatures = features.length
  console.log(`   📊 ${features.length} symbol-Features gefunden`)

  // ─── 3. Analysiere jede Feature ───
  console.log('\n[3/5] Analysiere Symbol-Referenzen...')

  const toRepair = []

  for (const feature of features) {
    const props = feature.properties || {}
    const iconId = props.iconId
    const imageUrl = props.imageUrl || ''

    // Keine iconId → nicht reparierbar, aber auch nicht unbedingt kaputt
    if (!iconId) {
      stats.validRefs++ // Oder neutral
      continue
    }

    // Prüfe ob iconId noch existiert
    const icon = iconById.get(iconId)
    if (icon) {
      stats.validRefs++
      continue
    }

    // ❌ Broken reference
    stats.brokenRefs++

    // Versuche Reparatur-Strategien
    let repairedId = null
    let repairMethod = null

    // Strategie 1: via migratedFromIconId
    const ts = tsByMigratedId.get(iconId)
    if (ts && ts.iconId && iconById.has(ts.iconId)) {
      repairedId = ts.iconId
      repairMethod = 'migratedFromIconId'
    }

    // Strategie 2: via imageUrl (extrahiere Dateinamen)
    if (!repairedId && imageUrl) {
      const match = imageUrl.match(/\/api\/icons\/([^\/]+)\/image/)
      if (match) {
        // Die alte iconId war in der URL, aber die ist ja gelöscht
        // Wir können hier nicht viel machen
      }
    }

    // Strategie 3: via Name-Matching (wenn iconId ein bekannter Name war)
    // Nicht anwendbar, da iconId eine UUID ist

    if (repairedId) {
      stats.repaired++
      toRepair.push({
        featureId: feature.id,
        projectId: feature.projectId,
        projectTitle: feature.project?.title || '(unbekannt)',
        oldIconId: iconId,
        newIconId: repairedId,
        repairMethod,
        properties: props,
      })
    } else {
      stats.notRepairable++
      stats.details.push({
        featureId: feature.id,
        projectId: feature.projectId,
        projectTitle: feature.project?.title || '(unbekannt)',
        iconId,
        reason: 'Keine Zuordnung möglich (iconId nicht in migratedFromIconId)',
        properties: JSON.stringify(props).substring(0, 200),
      })
    }
  }

  // ─── 4. Ergebnis-Anzeige ───
  console.log('\n[4/5] Ergebnis-Zusammenfassung')
  console.log('────────────────────────────────────────')
  console.log(`   Gesamt geprüfte Features:     ${stats.totalFeatures}`)
  console.log(`   ✅ Gültige Referenzen:         ${stats.validRefs}`)
  console.log(`   ❌ Kaputte Referenzen:         ${stats.brokenRefs}`)
  console.log(`   🔧 Automatisch reparierbar:    ${stats.repaired}`)
  console.log(`   ⚠️  Nicht reparierbar:          ${stats.notRepairable}`)

  if (stats.details.length > 0) {
    console.log('\n   Nicht reparierbare Features (erste 10):')
    for (const d of stats.details.slice(0, 10)) {
      console.log(`     - Feature ${d.featureId} in "${d.projectTitle}"`)
      console.log(`       iconId: ${d.iconId}`)
      console.log(`       Grund: ${d.reason}`)
    }
    if (stats.details.length > 10) {
      console.log(`     ... und ${stats.details.length - 10} weitere`)
    }
  }

  // ─── 5. Apply (nur wenn --apply) ───
  if (IS_APPLY && toRepair.length > 0) {
    console.log('\n[5/5] Wende Reparaturen an...')

    // Backup erstellen
    const backupPath = path.join(__dirname, `feature-backup-${Date.now()}.json`)
    const backup = toRepair.map(r => ({
      featureId: r.featureId,
      oldIconId: r.oldIconId,
      newIconId: r.newIconId,
      repairMethod: r.repairMethod,
      oldProperties: r.properties,
    }))
    fs.writeFileSync(backupPath, JSON.stringify(backup, null, 2))
    console.log(`   💾 Backup erstellt: ${backupPath}`)

    // Reparaturen durchführen
    let applied = 0
    for (const r of toRepair) {
      try {
        const newProps = {
          ...r.properties,
          iconId: r.newIconId,
        }
        await prisma.feature.update({
          where: { id: r.featureId },
          data: { properties: newProps },
        })
        applied++
        console.log(`   ✅ Feature ${r.featureId}: ${r.oldIconId} → ${r.newIconId} (${r.repairMethod})`)
      } catch (e) {
        console.error(`   ❌ Feature ${r.featureId}: Update fehlgeschlagen - ${e.message}`)
      }
    }
    console.log(`\n   ✅ ${applied}/${toRepair.length} Reparaturen erfolgreich angewendet`)
  } else if (IS_APPLY) {
    console.log('\n[5/5] Keine Reparaturen notwendig.')
  } else {
    console.log('\n[5/5] DRY-RUN abgeschlossen (keine Änderungen).')
    if (toRepair.length > 0) {
      console.log(`   Zum Anwenden: node prisma/repair-features.js --apply`)
    }
  }

  console.log('\n✅ Feature-Repair abgeschlossen')
}

repair()
  .then(async () => { await prisma.$disconnect() })
  .catch(async (e) => {
    console.error('❌ Fehler:', e)
    await prisma.$disconnect()
    process.exit(1)
  })
