/**
 * Betriebliche Aufwendungen — formula-based rows + category sums
 *
 * Computes formula-driven operating expenses (Fortbildung, Reisekosten, etc.),
 * Gewerbesteuer, marketing, Berufsgenossenschaft, category sums, and Gesamtkosten.
 * Also computes Cloud-Hosting formula in Materialaufwand.
 */

import { Pool } from 'pg'
import {
  MonthlyValues, MONTHS, FOUNDING_MONTH,
  emptyMonthly,
  FPBetrieblicheAufwendungen,
} from './types'
import { sumRows } from './engine-sheets'

type FPMaterialaufwand = import('./types').FPMaterialaufwand

export interface BetriebContext {
  totalBrutto: MonthlyValues
  totalPersonal: MonthlyValues
  totalAfa: MonthlyValues
  totalRevenue: MonthlyValues
  totalMaterial: MonthlyValues
  headcount: MonthlyValues
  totalBestandskunden: MonthlyValues
}

/**
 * Compute Cloud-Hosting formula in Materialaufwand.
 */
export async function computeCloudHosting(
  pool: Pool,
  matRows: FPMaterialaufwand[],
  totalBestandskunden: MonthlyValues,
): Promise<void> {
  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
  }
}

/**
 * Compute all formula-based betriebliche aufwendungen rows and sums.
 * Writes computed values back to DB.
 */
export async function computeBetrieblicheAufwendungen(
  pool: Pool,
  betrieb: FPBetrieblicheAufwendungen[],
  ctx: BetriebContext,
): Promise<{ totalSonstige: MonthlyValues; totalGesamt: MonthlyValues }> {
  const NUM_FOUNDERS = 2
  const hcWithoutFounders = emptyMonthly()
  for (let m = 1; m <= MONTHS; m++) {
    hcWithoutFounders[`m${m}`] = Math.max(0, ctx.headcount[`m${m}`] - NUM_FOUNDERS)
  }

  // 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: ctx.headcount },
    { label: 'Bewirtungskosten (F)', perUnit: 50, source: ctx.totalBestandskunden },
    { label: 'Internet/Mobilfunk (F)', perUnit: 50, source: ctx.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/Buero): ~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((ctx.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((ctx.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
  }

  // 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(ctx.totalPersonal), persBetrieb.id])
    persBetrieb.values = ctx.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(ctx.totalAfa), abrBetrieb.id])
    abrBetrieb.values = ctx.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 = ctx.totalRevenue[`m${m}`] || 0
      const mat = ctx.totalMaterial[`m${m}`] || 0
      const pers = ctx.totalPersonal[`m${m}`] || 0
      const afa = ctx.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}`] = (ctx.totalPersonal[`m${m}`] || 0) + (ctx.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
  }

  return {
    totalSonstige,
    totalGesamt: gesamtBetrieb?.values || emptyMonthly(),
  }
}
