/**
 * Finanzplan Compute Engine
 *
 * Dependency order:
 *   Personalkosten (independent inputs)
 *   Investitionen (independent inputs)
 *   Kunden → Umsatzerlöse → Materialaufwand
 *   Betriebliche Aufwendungen (needs Personal + Invest)
 *   Sonst. betr. Erträge (independent)
 *   Liquidität (aggregates all above)
 *   GuV (annual summary)
 */

import { Pool } from 'pg'
import {
  MonthlyValues, AnnualValues, MONTHS, FOUNDING_MONTH,
  emptyMonthly, sumMonthly, annualSums, dateToMonth, monthToDate,
  FPPersonalkosten, FPInvestitionen, FPBetrieblicheAufwendungen,
  FPLiquiditaet, FPComputeResult
} from './types'

// --- Sheet Calculators ---

export function computePersonalkosten(positions: FPPersonalkosten[]): FPPersonalkosten[] {
  return positions.map(p => {
    const brutto = emptyMonthly()
    const sozial = emptyMonthly()
    const total = emptyMonthly()

    if (!p.start_date || !p.brutto_monthly) return { ...p, values_brutto: brutto, values_sozial: sozial, values_total: total }

    const startDate = new Date(p.start_date)
    const startM = dateToMonth(startDate.getFullYear(), startDate.getMonth() + 1)
    const endM = p.end_date
      ? dateToMonth(new Date(p.end_date).getFullYear(), new Date(p.end_date).getMonth() + 1)
      : MONTHS

    for (let m = Math.max(1, startM); m <= Math.min(MONTHS, endM); m++) {
      const { year } = monthToDate(m)
      const yearsFromStart = year - startDate.getFullYear()
      const raise = Math.pow(1 + (p.annual_raise_pct || 0) / 100, yearsFromStart)
      const monthlyBrutto = Math.round(p.brutto_monthly * raise)

      brutto[`m${m}`] = monthlyBrutto
      sozial[`m${m}`] = Math.round(monthlyBrutto * (p.ag_sozial_pct || 20.425) / 100)
      total[`m${m}`] = brutto[`m${m}`] + sozial[`m${m}`]
    }

    return { ...p, values_brutto: brutto, values_sozial: sozial, values_total: total }
  })
}

export function computeInvestitionen(items: FPInvestitionen[]): FPInvestitionen[] {
  return items.map(item => {
    const invest = emptyMonthly()
    const afa = emptyMonthly()

    if (!item.purchase_date || !item.purchase_amount) return { ...item, values_invest: invest, values_afa: afa }

    const d = new Date(item.purchase_date)
    const purchaseM = dateToMonth(d.getFullYear(), d.getMonth() + 1)

    if (purchaseM >= 1 && purchaseM <= MONTHS) {
      invest[`m${purchaseM}`] = item.purchase_amount
    }

    // AfA (linear depreciation)
    if (item.afa_years && item.afa_years > 0) {
      const afaMonths = item.afa_years * 12
      const monthlyAfa = Math.round(item.purchase_amount / afaMonths)
      for (let m = purchaseM; m < purchaseM + afaMonths && m <= MONTHS; m++) {
        if (m >= 1) afa[`m${m}`] = monthlyAfa
      }
    } else {
      // GWG: full depreciation in purchase month
      if (purchaseM >= 1 && purchaseM <= MONTHS) {
        afa[`m${purchaseM}`] = item.purchase_amount
      }
    }

    return { ...item, values_invest: invest, values_afa: afa }
  })
}

function sumRows(rows: { values: MonthlyValues }[]): MonthlyValues {
  const result = emptyMonthly()
  for (const row of rows) {
    for (let m = 1; m <= MONTHS; m++) {
      result[`m${m}`] += row.values[`m${m}`] || 0
    }
  }
  return result
}

function sumField(rows: { [key: string]: MonthlyValues }[], field: string): MonthlyValues {
  const result = emptyMonthly()
  for (const row of rows) {
    const v = row[field] as MonthlyValues
    if (!v) continue
    for (let m = 1; m <= MONTHS; m++) {
      result[`m${m}`] += v[`m${m}`] || 0
    }
  }
  return result
}

// --- Main Engine ---

export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise<FPComputeResult> {
  // 1. Load all editable data from DB
  const [
    personalRows,
    investRows,
    betriebRows,
    liquidRows,
    kundenSummary,
    umsatzRows,
    materialRows,
  ] = await Promise.all([
    pool.query('SELECT * FROM fp_personalkosten WHERE scenario_id = $1 ORDER BY sort_order', [scenarioId]),
    pool.query('SELECT * FROM fp_investitionen WHERE scenario_id = $1 ORDER BY sort_order', [scenarioId]),
    pool.query('SELECT * FROM fp_betriebliche_aufwendungen WHERE scenario_id = $1 ORDER BY sort_order', [scenarioId]),
    pool.query('SELECT * FROM fp_liquiditaet WHERE scenario_id = $1 ORDER BY sort_order', [scenarioId]),
    pool.query('SELECT * FROM fp_kunden_summary WHERE scenario_id = $1 ORDER BY sort_order', [scenarioId]),
    pool.query('SELECT * FROM fp_umsatzerloese WHERE scenario_id = $1 ORDER BY sort_order', [scenarioId]),
    pool.query('SELECT * FROM fp_materialaufwand WHERE scenario_id = $1 ORDER BY sort_order', [scenarioId]),
  ])

  // 2. Compute Personalkosten
  const personal = computePersonalkosten(personalRows.rows as FPPersonalkosten[])
  const totalBrutto = sumField(personal as any, 'values_brutto')
  const totalSozial = sumField(personal as any, 'values_sozial')
  const totalPersonal = sumField(personal as any, 'values_total')
  const headcount = emptyMonthly()
  for (let m = 1; m <= MONTHS; m++) {
    headcount[`m${m}`] = personal.filter(p => (p.values_total[`m${m}`] || 0) > 0).length
  }

  // Write computed values back to DB
  for (const p of personal) {
    await pool.query(
      'UPDATE fp_personalkosten SET values_brutto = $1, values_sozial = $2, values_total = $3 WHERE id = $4',
      [JSON.stringify(p.values_brutto), JSON.stringify(p.values_sozial), JSON.stringify(p.values_total), p.id]
    )
  }

  // 3. Compute Investitionen
  const invest = computeInvestitionen(investRows.rows as FPInvestitionen[])
  const totalInvest = sumField(invest as any, 'values_invest')
  const totalAfa = sumField(invest as any, 'values_afa')

  for (const i of invest) {
    await pool.query(
      'UPDATE fp_investitionen SET values_invest = $1, values_afa = $2 WHERE id = $3',
      [JSON.stringify(i.values_invest), JSON.stringify(i.values_afa), i.id]
    )
  }

  // 4. Umsatzerlöse (quantity × price)
  const prices = (umsatzRows.rows as FPUmsatzerloese[]).filter(r => r.section === 'price')
  const quantities = (umsatzRows.rows as FPUmsatzerloese[]).filter(r => r.section === 'quantity')
  const revenueRows = (umsatzRows.rows as FPUmsatzerloese[]).filter(r => r.section === 'revenue')
  const totalRevenue = emptyMonthly()

  // Revenue = quantity × price for each module (if qty+price exist)
  // Match by tier name extracted from parentheses, or exact label match
  const extractTier = (label: string) => { const m = label.match(/\(([^)]+)\)/); return m ? m[1] : label }
  // Revenue rows WITHOUT matching qty/price are kept as-is (e.g. Beratung & Service)
  for (const rev of revenueRows) {
    if (rev.row_label === 'GESAMTUMSATZ') continue
    const tier = extractTier(rev.row_label)
    const qty = quantities.find(q => extractTier(q.row_label) === tier) || quantities.find(q => q.row_label === rev.row_label)
    const price = prices.find(p => extractTier(p.row_label) === tier) || prices.find(p => p.row_label === rev.row_label)
    if (qty && price) {
      for (let m = 1; m <= MONTHS; m++) {
        const v = (qty.values[`m${m}`] || 0) * (price.values[`m${m}`] || 0)
        rev.values[`m${m}`] = Math.round(v)
      }
      await pool.query('UPDATE fp_umsatzerloese SET values = $1 WHERE id = $2', [JSON.stringify(rev.values), rev.id])
    }
    // Add ALL revenue rows to total (computed or manual)
    for (let m = 1; m <= MONTHS; m++) {
      totalRevenue[`m${m}`] += rev.values[`m${m}`] || 0
    }
  }
  // Update GESAMTUMSATZ
  const gesamtUmsatz = revenueRows.find(r => r.row_label === 'GESAMTUMSATZ')
  if (gesamtUmsatz) {
    await pool.query('UPDATE fp_umsatzerloese SET values = $1 WHERE id = $2', [JSON.stringify(totalRevenue), gesamtUmsatz.id])
  }

  // 5. Materialaufwand (quantity × unit_cost) — simplified
  const matCosts = (materialRows.rows as FPMaterialaufwand[]).filter(r => r.section === 'cost')
  const matUnitCosts = (materialRows.rows as FPMaterialaufwand[]).filter(r => r.section === 'unit_cost')
  const totalMaterial = emptyMonthly()

  for (const cost of matCosts) {
    if (cost.row_label === 'SUMME') continue
    const uc = matUnitCosts.find(u => u.row_label === cost.row_label)
    const qty = quantities.find(q => q.row_label === cost.row_label)
    if (uc && qty) {
      for (let m = 1; m <= MONTHS; m++) {
        const v = (qty.values[`m${m}`] || 0) * (uc.values[`m${m}`] || 0)
        cost.values[`m${m}`] = Math.round(v)
      }
      await pool.query('UPDATE fp_materialaufwand SET values = $1 WHERE id = $2', [JSON.stringify(cost.values), cost.id])
    }
    // Add ALL cost rows to total (computed or manual)
    for (let m = 1; m <= MONTHS; m++) {
      totalMaterial[`m${m}`] += cost.values[`m${m}`] || 0
    }
  }
  const matSumme = matCosts.find(r => r.row_label === 'SUMME')
  if (matSumme) {
    await pool.query('UPDATE fp_materialaufwand SET values = $1 WHERE id = $2', [JSON.stringify(totalMaterial), matSumme.id])
  }

  // 5b. Headcount without founders (for formula-based costs)
  const NUM_FOUNDERS = 2
  const hcWithoutFounders = emptyMonthly()
  for (let m = 1; m <= MONTHS; m++) {
    hcWithoutFounders[`m${m}`] = Math.max(0, headcount[`m${m}`] - NUM_FOUNDERS)
  }

  // 5c. Total Bestandskunden (for Bewirtungskosten — uses totalBestandskunden from Serverkosten above)
  // Also load enterprise customers separately for legacy compatibility
  const kundenRows = await pool.query(
    "SELECT segment_name, row_label, values FROM fp_kunden WHERE scenario_id = $1 AND row_label LIKE 'Bestandskunden%' ORDER BY sort_order",
    [scenarioId]
  )
  const enterpriseKunden = emptyMonthly()
  for (const row of kundenRows.rows) {
    if (row.segment_name?.toLowerCase().includes('enterprise')) {
      for (let m = 1; m <= MONTHS; m++) {
        enterpriseKunden[`m${m}`] = row.values?.[`m${m}`] || 0
      }
    }
  }

  // 6. Betriebliche Aufwendungen — compute formula-based rows + sum rows
  const betrieb = betriebRows.rows as FPBetrieblicheAufwendungen[]

  // Pre-compute total Bestandskunden (needed for Bewirtungskosten + Serverkosten)
  const totalBestandskunden = emptyMonthly()
  for (const row of kundenRows.rows) {
    const rl = (row as { row_label?: string }).row_label || ''
    if (rl.includes('Bestandskunden') && !rl.includes('gesamt')) {
      for (let m = 1; m <= MONTHS; m++) {
        totalBestandskunden[`m${m}`] += row.values?.[`m${m}`] || 0
      }
    }
  }

  // Formula-based rows: derive from headcount (excl. founders) or customers
  const formulaRows: { label: string; perUnit: number; source: MonthlyValues }[] = [
    { label: 'Fort-/Weiterbildungskosten (F)', perUnit: 300, source: hcWithoutFounders },
    // KFZ costs are manual (from Jan 2028), not formula-based
    { label: 'Reisekosten (F)', perUnit: 75, source: headcount },
    { label: 'Bewirtungskosten (F)', perUnit: 50, source: totalBestandskunden },
    { label: 'Internet/Mobilfunk (F)', perUnit: 50, source: headcount },
  ]

  for (const fr of formulaRows) {
    const row = betrieb.find(r => r.row_label === fr.label)
    if (row) {
      const computed = emptyMonthly()
      for (let m = FOUNDING_MONTH; m <= MONTHS; m++) {
        computed[`m${m}`] = Math.round((fr.source[`m${m}`] || 0) * fr.perUnit)
      }
      await pool.query('UPDATE fp_betriebliche_aufwendungen SET values = $1 WHERE id = $2', [JSON.stringify(computed), row.id])
      row.values = computed
    }
  }

  // Berufsgenossenschaft (VBG IT/Büro): ~0.5% of total brutto payroll
  const bgRow = betrieb.find(r => r.row_label.includes('Berufsgenossenschaft'))
  if (bgRow) {
    const computed = emptyMonthly()
    for (let m = FOUNDING_MONTH; m <= MONTHS; m++) {
      computed[`m${m}`] = Math.round((totalBrutto[`m${m}`] || 0) * 0.005)
    }
    await pool.query('UPDATE fp_betriebliche_aufwendungen SET values = $1 WHERE id = $2', [JSON.stringify(computed), bgRow.id])
    bgRow.values = computed
  }

  // Allgemeine Marketingkosten: 8% of revenue (2026-2028), 10% from 2029
  const marketingRow = betrieb.find(r => r.row_label.includes('Allgemeine Marketingkosten'))
  if (marketingRow) {
    const computed = emptyMonthly()
    for (let m = FOUNDING_MONTH; m <= MONTHS; m++) {
      const rate = m <= 36 ? 0.08 : 0.10 // m36 = Dec 2028
      computed[`m${m}`] = Math.round((totalRevenue[`m${m}`] || 0) * rate)
    }
    await pool.query('UPDATE fp_betriebliche_aufwendungen SET values = $1 WHERE id = $2', [JSON.stringify(computed), marketingRow.id])
    marketingRow.values = computed
  }

  // Serverkosten now in Materialaufwand — compute Cloud-Hosting formula there
  const matRows = materialRows.rows as FPMaterialaufwand[]
  const cloudRow = matRows.find(r => r.row_label.includes('Cloud-Hosting'))
  if (cloudRow) {
    const computed = emptyMonthly()
    for (let m = FOUNDING_MONTH; m <= MONTHS; m++) {
      const kunden = totalBestandskunden[`m${m}`] || 0
      const extraKunden = Math.max(0, kunden - 10) // first 10 included in base
      computed[`m${m}`] = Math.round(extraKunden * 100 + 1500)
    }
    await pool.query('UPDATE fp_materialaufwand SET values = $1 WHERE id = $2', [JSON.stringify(computed), cloudRow.id])
    cloudRow.values = computed
  }

  // Update Personalkosten row
  const persBetrieb = betrieb.find(r => r.row_label === 'Personalkosten')
  if (persBetrieb) {
    await pool.query('UPDATE fp_betriebliche_aufwendungen SET values = $1 WHERE id = $2', [JSON.stringify(totalPersonal), persBetrieb.id])
    persBetrieb.values = totalPersonal
  }
  // Update Abschreibungen row
  const abrBetrieb = betrieb.find(r => r.row_label === 'Abschreibungen')
  if (abrBetrieb) {
    await pool.query('UPDATE fp_betriebliche_aufwendungen SET values = $1 WHERE id = $2', [JSON.stringify(totalAfa), abrBetrieb.id])
    abrBetrieb.values = totalAfa
  }

  // Gewerbesteuer (F): 12.25% of monthly profit (only when positive)
  // Monthly profit = Revenue - Material - Personnel - AfA - other opex (excl. taxes)
  const gewStRow = betrieb.find(r => r.row_label.includes('Gewerbesteuer'))
  if (gewStRow) {
    const nonTaxOpex = betrieb.filter(r =>
      r.category !== 'steuern' && r.category !== 'personal' && r.category !== 'abschreibungen' &&
      !r.is_sum_row && !r.row_label.includes('Summe') && !r.row_label.includes('SUMME')
    )
    const computed = emptyMonthly()
    for (let m = FOUNDING_MONTH; m <= MONTHS; m++) {
      const rev = totalRevenue[`m${m}`] || 0
      const mat = totalMaterial[`m${m}`] || 0
      const pers = totalPersonal[`m${m}`] || 0
      const afa = totalAfa[`m${m}`] || 0
      let opex = 0
      for (const r of nonTaxOpex) { opex += r.values[`m${m}`] || 0 }
      const profit = rev - mat - pers - afa - opex
      computed[`m${m}`] = profit > 0 ? Math.round(profit * 0.1225) : 0
    }
    await pool.query('UPDATE fp_betriebliche_aufwendungen SET values = $1 WHERE id = $2', [JSON.stringify(computed), gewStRow.id])
    gewStRow.values = computed
  }

  // Compute category sums
  const categories = ['steuern', 'versicherungen', 'besondere', 'marketing', 'sonstige']
  for (const cat of categories) {
    const sumRow = betrieb.find(r => r.category === cat && r.is_sum_row)
    const detailRows = betrieb.filter(r => r.category === cat && !r.is_sum_row)
    if (sumRow && detailRows.length > 0) {
      const s = sumRows(detailRows)
      await pool.query('UPDATE fp_betriebliche_aufwendungen SET values = $1 WHERE id = $2', [JSON.stringify(s), sumRow.id])
      sumRow.values = s
    }
  }

  // Summe sonstige (ohne Personal, Abschreibungen)
  const sonstSumme = betrieb.find(r => r.row_label.includes('Summe sonstige'))
  if (sonstSumme) {
    const nonPersonNonAbr = betrieb.filter(r =>
      r.row_label !== 'Personalkosten' && r.row_label !== 'Abschreibungen' &&
      !r.row_label.includes('Summe sonstige') && !r.row_label.includes('Gesamtkosten') &&
      !r.is_sum_row && r.category !== 'personal' && r.category !== 'abschreibungen'
    )
    const s = sumRows(nonPersonNonAbr)
    await pool.query('UPDATE fp_betriebliche_aufwendungen SET values = $1 WHERE id = $2', [JSON.stringify(s), sonstSumme.id])
    sonstSumme.values = s
  }

  // Gesamtkosten
  const gesamtBetrieb = betrieb.find(r => r.row_label.includes('Gesamtkosten') || r.row_label.includes('SUMME Betriebliche'))
  const totalSonstige = sonstSumme?.values || emptyMonthly()
  if (gesamtBetrieb) {
    const g = emptyMonthly()
    for (let m = 1; m <= MONTHS; m++) {
      g[`m${m}`] = (totalPersonal[`m${m}`] || 0) + (totalAfa[`m${m}`] || 0) + (totalSonstige[`m${m}`] || 0)
    }
    await pool.query('UPDATE fp_betriebliche_aufwendungen SET values = $1 WHERE id = $2', [JSON.stringify(g), gesamtBetrieb.id])
    gesamtBetrieb.values = g
  }

  // 7. Liquidität
  const liquid = liquidRows.rows as FPLiquiditaet[]
  const findLiq = (label: string) => liquid.find(r => r.row_label === label)

  // Computed rows
  const liqUmsatz = findLiq('Umsatzerlöse')
  if (liqUmsatz) {
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(totalRevenue), liqUmsatz.id])
    liqUmsatz.values = totalRevenue
  }
  const liqMaterial = findLiq('Materialaufwand')
  if (liqMaterial) {
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(totalMaterial), liqMaterial.id])
    liqMaterial.values = totalMaterial
  }
  const liqPersonal = findLiq('Personalkosten')
  if (liqPersonal) {
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(totalPersonal), liqPersonal.id])
    liqPersonal.values = totalPersonal
  }
  const liqSonstige = findLiq('Sonstige Kosten')
  if (liqSonstige) {
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(totalSonstige), liqSonstige.id])
    liqSonstige.values = totalSonstige
  }
  const liqInvest = findLiq('Investitionen')
  if (liqInvest) {
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(totalInvest), liqInvest.id])
    liqInvest.values = totalInvest
  }

  // Compute sums and rolling balance
  // WICHTIG: Überschuss = nur operativer Cashflow (ohne Kapitaleinzahlungen)
  const sumEin = findLiq('Summe EINZAHLUNGEN')
  const sumAus = findLiq('Summe AUSZAHLUNGEN')
  const uebVorInv = findLiq('ÜBERSCHUSS VOR INVESTITIONEN')
  const uebVorEnt = findLiq('ÜBERSCHUSS VOR ENTNAHMEN')
  const ueberschuss = findLiq('ÜBERSCHUSS')
  const kontostand = findLiq('Kontostand zu Beginn des Monats')
  const liquiditaet = findLiq('LIQUIDITÄT')

  // Dynamically categorize rows by row_type instead of hardcoded labels
  // Operative Einzahlungen (OHNE Eigenkapital, Fremdkapital, Stammkapital, Wandeldarlehen)
  const einzahlungenOperativ = ['Umsatzerlöse', 'Sonst. betriebl. Erträge', 'Anzahlungen']
  // Finanzierung: match any row with these keywords (handles renamed labels)
  const finanzierungRows = liquid.filter(r =>
    r.row_type === 'einzahlung' &&
    !einzahlungenOperativ.includes(r.row_label) &&
    !r.row_label.includes('Summe')
  )
  // Operative Auszahlungen
  const auszahlungenOperativ = ['Materialaufwand', 'Personalkosten', 'Sonstige Kosten', 'Umsatzsteuer', 'Gewerbesteuer', 'Körperschaftsteuer']
  // Finanz-Auszahlungen: any auszahlung not in operativ list
  const finanzAuszahlungRows = liquid.filter(r =>
    r.row_type === 'auszahlung' &&
    !auszahlungenOperativ.includes(r.row_label) &&
    !r.row_label.includes('Summe')
  )

  // Summe EINZAHLUNGEN = nur operativ (für die Zeile "Summe Einzahlungen")
  if (sumEin) {
    const s = emptyMonthly()
    for (const label of einzahlungenOperativ) {
      const row = findLiq(label)
      if (row) for (let m = 1; m <= MONTHS; m++) s[`m${m}`] += Math.round(row.values[`m${m}`] || 0)
    }
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(s), sumEin.id])
    sumEin.values = s
  }

  // Summe AUSZAHLUNGEN = nur operativ
  if (sumAus) {
    const s = emptyMonthly()
    for (const label of auszahlungenOperativ) {
      const row = findLiq(label)
      if (row) for (let m = 1; m <= MONTHS; m++) s[`m${m}`] += Math.round(row.values[`m${m}`] || 0)
    }
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(s), sumAus.id])
    sumAus.values = s
  }

  // OPERATIVER ÜBERSCHUSS VOR INVESTITIONEN = operative Einzahlungen - operative Auszahlungen
  if (uebVorInv && sumEin && sumAus) {
    const s = emptyMonthly()
    for (let m = 1; m <= MONTHS; m++) s[`m${m}`] = Math.round((sumEin.values[`m${m}`] || 0) - (sumAus.values[`m${m}`] || 0))
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(s), uebVorInv.id])
    uebVorInv.values = s
  }

  // ÜBERSCHUSS VOR ENTNAHMEN = Operativer Überschuss - Investitionen
  if (uebVorEnt && uebVorInv && liqInvest) {
    const s = emptyMonthly()
    for (let m = 1; m <= MONTHS; m++) s[`m${m}`] = Math.round((uebVorInv.values[`m${m}`] || 0) - (liqInvest.values[`m${m}`] || 0))
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(s), uebVorEnt.id])
    uebVorEnt.values = s
  }

  // ÜBERSCHUSS = Überschuss vor Entnahmen - Entnahmen (immer noch rein operativ)
  const entnahmen = findLiq('Kapitalentnahmen/Ausschüttungen')
  if (ueberschuss && uebVorEnt && entnahmen) {
    const s = emptyMonthly()
    for (let m = 1; m <= MONTHS; m++) s[`m${m}`] = Math.round((uebVorEnt.values[`m${m}`] || 0) - (entnahmen.values[`m${m}`] || 0))
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(s), ueberschuss.id])
    ueberschuss.values = s
  }

  // Rolling Kontostand: Vormonat + Operativer Überschuss + Finanzierung
  // Finanzierung = Eigenkapital + Fremdkapital - Kreditrückzahlungen
  if (kontostand && liquiditaet && ueberschuss) {
    // Berechne monatliche Finanzierungs-Cashflows
    const finCF = emptyMonthly()
    for (const row of finanzierungRows) {
      for (let m = 1; m <= MONTHS; m++) finCF[`m${m}`] += Math.round(row.values[`m${m}`] || 0)
    }
    for (const row of finanzAuszahlungRows) {
      for (let m = 1; m <= MONTHS; m++) finCF[`m${m}`] -= Math.round(row.values[`m${m}`] || 0)
    }

    const ks = emptyMonthly()
    const lq = emptyMonthly()
    for (let m = 1; m <= MONTHS; m++) {
      ks[`m${m}`] = m === 1 ? 0 : Math.round(lq[`m${m - 1}`])
      // LIQUIDITÄT = Kontostand + Operativer Überschuss + Finanzierung
      lq[`m${m}`] = Math.round(ks[`m${m}`] + (ueberschuss.values[`m${m}`] || 0) + (finCF[`m${m}`] || 0))
    }
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(ks), kontostand.id])
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(lq), liquiditaet.id])
    kontostand.values = ks
    liquiditaet.values = lq
  }

  // 8. GuV — compute annual values
  const guv: AnnualValues[] = []
  const umsatzAnnual = annualSums(totalRevenue)
  const materialAnnual = annualSums(totalMaterial)
  const personalBruttoAnnual = annualSums(totalBrutto)
  const personalSozialAnnual = annualSums(totalSozial)
  const personalAnnual = annualSums(totalPersonal)
  const afaAnnual = annualSums(totalAfa)
  const sonstigeAnnual = annualSums(totalSonstige)

  // Write GuV rows
  // Rohergebnis = Gesamtleistung - Materialaufwand
  const rohergebnis: AnnualValues = {}
  for (let y = 2026; y <= 2030; y++) {
    const k = `y${y}`
    rohergebnis[k] = Math.round((umsatzAnnual[k] || 0) - (materialAnnual[k] || 0))
  }

  const guvUpdates: { label: string; values: AnnualValues }[] = [
    { label: 'Umsatzerlöse', values: umsatzAnnual },
    { label: 'Gesamtleistung', values: umsatzAnnual },
    { label: 'Summe Materialaufwand', values: materialAnnual },
    { label: 'Rohergebnis', values: rohergebnis },
    { label: 'Löhne und Gehälter', values: personalBruttoAnnual },
    { label: 'Soziale Abgaben', values: personalSozialAnnual },
    { label: 'Summe Personalaufwand', values: personalAnnual },
    { label: 'Abschreibungen', values: afaAnnual },
    { label: 'Sonst. betriebl. Aufwendungen', values: sonstigeAnnual },
  ]

  for (const { label, values } of guvUpdates) {
    await pool.query(
      'UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3',
      [JSON.stringify(values), scenarioId, label]
    )
  }

  // EBIT (Betriebsergebnis)
  const ebit: AnnualValues = {}
  for (let y = 2026; y <= 2030; y++) {
    const k = `y${y}`
    ebit[k] = Math.round((umsatzAnnual[k] || 0) - (materialAnnual[k] || 0) - (personalAnnual[k] || 0) - (afaAnnual[k] || 0) - (sonstigeAnnual[k] || 0))
  }
  await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(ebit), scenarioId, 'EBIT'])

  // Steuerberechnung (nur auf Gewinne, mit Verlustvortrag)
  // Stockach 78333: Hebesatz 350%
  // Gewerbesteuer = 3,5% × 3,5 = 12,25%
  // Körperschaftsteuer = 15% + 5,5% Soli = 15,825%
  // Gesamt: ~28,075%
  const GEWERBESTEUER_RATE = 0.035 * 3.5   // 12,25%
  const KOERPERSCHAFTSTEUER_RATE = 0.15 * 1.055  // 15,825% (inkl. Soli)

  const gewerbesteuer: AnnualValues = {}
  const koerperschaftsteuer: AnnualValues = {}
  const steuernGesamt: AnnualValues = {}
  const ergebnisNachSteuern: AnnualValues = {}
  let verlustvortrag = 0  // kumulierter Verlustvortrag

  for (let y = 2026; y <= 2030; y++) {
    const k = `y${y}`
    const gewinn = ebit[k] || 0

    if (gewinn <= 0) {
      // Verlust: keine Steuern, Verlustvortrag aufbauen
      verlustvortrag += Math.abs(gewinn)
      gewerbesteuer[k] = 0
      koerperschaftsteuer[k] = 0
      steuernGesamt[k] = 0
      ergebnisNachSteuern[k] = Math.round(gewinn)
    } else {
      // Gewinn: Verlustvortrag verrechnen
      // Bis 1 Mio EUR: 100% verrechenbar
      // Über 1 Mio EUR: nur 60% verrechenbar (Mindestbesteuerung)
      let verrechenbar = 0
      if (verlustvortrag > 0) {
        if (gewinn <= 1000000) {
          verrechenbar = Math.min(verlustvortrag, gewinn)
        } else {
          verrechenbar = Math.min(verlustvortrag, 1000000 + (gewinn - 1000000) * 0.6)
        }
        verlustvortrag -= verrechenbar
      }

      const zuVersteuern = Math.max(0, gewinn - verrechenbar)
      const gst = Math.round(zuVersteuern * GEWERBESTEUER_RATE)
      const kst = Math.round(zuVersteuern * KOERPERSCHAFTSTEUER_RATE)

      gewerbesteuer[k] = gst
      koerperschaftsteuer[k] = kst
      steuernGesamt[k] = gst + kst
      ergebnisNachSteuern[k] = Math.round(gewinn - gst - kst)
    }
  }

  await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(gewerbesteuer), scenarioId, 'Gewerbesteuer'])
  await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(koerperschaftsteuer), scenarioId, 'Körperschaftssteuer'])
  await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(steuernGesamt), scenarioId, 'Steuern gesamt'])
  await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(ergebnisNachSteuern), scenarioId, 'Ergebnis nach Steuern'])
  await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(ergebnisNachSteuern), scenarioId, 'Jahresüberschuss'])

  // Steuern auch in Liquidität eintragen (monatlich = 1/12 des Jahresbetrags)
  const liqGewSt = findLiq('Gewerbesteuer')
  const liqKSt = findLiq('Körperschaftsteuer')
  if (liqGewSt) {
    const v = emptyMonthly()
    for (let y = 2026; y <= 2030; y++) {
      const jahresBetrag = gewerbesteuer[`y${y}`] || 0
      if (jahresBetrag > 0) {
        const monatlich = Math.round(jahresBetrag / 12)
        const startM = (y - 2026) * 12 + 1
        for (let m = startM; m <= startM + 11 && m <= MONTHS; m++) {
          v[`m${m}`] = monatlich
        }
      }
    }
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(v), liqGewSt.id])
    liqGewSt.values = v
  }
  if (liqKSt) {
    const v = emptyMonthly()
    for (let y = 2026; y <= 2030; y++) {
      const jahresBetrag = koerperschaftsteuer[`y${y}`] || 0
      if (jahresBetrag > 0) {
        const monatlich = Math.round(jahresBetrag / 12)
        const startM = (y - 2026) * 12 + 1
        for (let m = startM; m <= startM + 11 && m <= MONTHS; m++) {
          v[`m${m}`] = monatlich
        }
      }
    }
    await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(v), liqKSt.id])
    liqKSt.values = v
  }

  return {
    personalkosten: { total_brutto: totalBrutto, total_sozial: totalSozial, total: totalPersonal, positions: personal, headcount },
    investitionen: { total_invest: totalInvest, total_afa: totalAfa, items: invest },
    umsatzerloese: { total: totalRevenue },
    materialaufwand: { total: totalMaterial },
    betriebliche: { total_sonstige: totalSonstige, total_gesamt: gesamtBetrieb?.values || emptyMonthly() },
    liquiditaet: { rows: liquid, endstand: liquiditaet?.values || emptyMonthly() },
    guv: [ebit],
  }
}

// Import to fix type errors
type FPUmsatzerloese = import('./types').FPUmsatzerloese
type FPMaterialaufwand = import('./types').FPMaterialaufwand
