/**
 * GuV (Gewinn- und Verlustrechnung) — annual P&L computation
 *
 * Computes annual sums, EBIT, taxes (Gewerbesteuer, Koerperschaftsteuer)
 * with Verlustvortrag, and writes tax amounts back to Liquiditaet.
 */

import { Pool } from 'pg'
import {
  MonthlyValues, AnnualValues, MONTHS,
  emptyMonthly, annualSums,
  FPLiquiditaet,
} from './types'

export interface GuvContext {
  totalRevenue: MonthlyValues
  totalMaterial: MonthlyValues
  totalBrutto: MonthlyValues
  totalSozial: MonthlyValues
  totalPersonal: MonthlyValues
  totalAfa: MonthlyValues
  totalSonstige: MonthlyValues
}

/**
 * Compute GuV annual values, taxes, and write tax values to Liquiditaet.
 * Returns EBIT annual values.
 */
export async function computeGuV(
  pool: Pool,
  scenarioId: string,
  liquid: FPLiquiditaet[],
  ctx: GuvContext,
): Promise<AnnualValues[]> {
  const findLiq = (label: string) => liquid.find(r => r.row_label === label)

  const umsatzAnnual = annualSums(ctx.totalRevenue)
  const materialAnnual = annualSums(ctx.totalMaterial)
  const personalBruttoAnnual = annualSums(ctx.totalBrutto)
  const personalSozialAnnual = annualSums(ctx.totalSozial)
  const personalAnnual = annualSums(ctx.totalPersonal)
  const afaAnnual = annualSums(ctx.totalAfa)
  const sonstigeAnnual = annualSums(ctx.totalSonstige)

  // 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'])

  // Tax computation with Verlustvortrag
  const { gewerbesteuer, koerperschaftsteuer, steuernGesamt, ergebnisNachSteuern } = computeTaxes(ebit)

  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'])

  // Write taxes to Liquiditaet (monthly = 1/12 of annual amount)
  await writeTaxToLiquiditaet(pool, findLiq('Gewerbesteuer'), gewerbesteuer)
  await writeTaxToLiquiditaet(pool, findLiq('Körperschaftsteuer'), koerperschaftsteuer)

  return [ebit]
}

// --- Tax helpers ---

// Stockach 78333: Hebesatz 350%
// Gewerbesteuer = 3,5% x 3,5 = 12,25%
// Koerperschaftsteuer = 15% + 5,5% Soli = 15,825%
const GEWERBESTEUER_RATE = 0.035 * 3.5   // 12,25%
const KOERPERSCHAFTSTEUER_RATE = 0.15 * 1.055  // 15,825% (inkl. Soli)

function computeTaxes(ebit: AnnualValues) {
  const gewerbesteuer: AnnualValues = {}
  const koerperschaftsteuer: AnnualValues = {}
  const steuernGesamt: AnnualValues = {}
  const ergebnisNachSteuern: AnnualValues = {}
  let verlustvortrag = 0

  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
      // Ueber 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)
    }
  }

  return { gewerbesteuer, koerperschaftsteuer, steuernGesamt, ergebnisNachSteuern }
}

async function writeTaxToLiquiditaet(
  pool: Pool,
  liqRow: FPLiquiditaet | undefined,
  annualTax: AnnualValues,
): Promise<void> {
  if (!liqRow) return
  const v = emptyMonthly()
  for (let y = 2026; y <= 2030; y++) {
    const jahresBetrag = annualTax[`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), liqRow.id])
  liqRow.values = v
}
