/**
 * Liquiditaet — rolling cash balance computation
 *
 * Computes Einzahlungen/Auszahlungen sums (dynamic row_type-based),
 * Ueberschuss vor Investitionen/Entnahmen, and rolling Kontostand/Liquiditaet.
 */

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

export interface LiquiditaetContext {
  totalRevenue: MonthlyValues
  totalMaterial: MonthlyValues
  totalPersonal: MonthlyValues
  totalSonstige: MonthlyValues
  totalInvest: MonthlyValues
}

/**
 * Compute all liquidity rows and rolling balance.
 * Writes computed values back to DB.
 */
export async function computeLiquiditaet(
  pool: Pool,
  liquid: FPLiquiditaet[],
  ctx: LiquiditaetContext,
): Promise<{ endstand: MonthlyValues }> {
  const findLiq = (label: string) => liquid.find(r => r.row_label === label)

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

  // Compute sums and rolling balance — dynamic row_type-based (handles any label conventions)
  await computeRollingBalance(pool, liquid)

  return { endstand: liquid.find(r => r.row_type === 'kontostand' && r.row_label.includes('LIQUIDIT'))?.values || emptyMonthly() }
}

/**
 * Recompute Summe AUSZAHLUNGEN -> UEBERSCHUSS chain -> rolling balance.
 * Called both in initial pass and after tax values are written from GuV.
 */
export async function computeRollingBalance(
  pool: Pool,
  liquid: FPLiquiditaet[],
): Promise<void> {
  const findLiqMatch = (options: string[]) => liquid.find(r => options.includes(r.row_label))

  const sumEin = findLiqMatch(['Summe ERTRÄGE', 'Summe EINZAHLUNGEN'])
  const sumAus = findLiqMatch(['Summe AUSZAHLUNGEN'])
  const uebVorInv = findLiqMatch(['ÜBERSCHUSS VOR INVESTITIONEN', 'UEBERSCHUSS VOR INVESTITIONEN'])
  const uebVorEnt = findLiqMatch(['ÜBERSCHUSS VOR ENTNAHMEN', 'UEBERSCHUSS VOR ENTNAHMEN'])
  const ueberschuss = findLiqMatch(['ÜBERSCHUSS', 'UEBERSCHUSS'])
  const liqInvest = liquid.find(r => r.row_label === 'Investitionen')
  // Kontostand: label varies per scenario (with/without parentheses)
  const kontostand = liquid.find(r => r.row_type === 'kontostand' && !r.row_label.includes('LIQUIDIT'))
  const liquiditaet = liquid.find(r => r.row_type === 'kontostand' && r.row_label.includes('LIQUIDIT'))

  // Summe ERTRAEGE = ALL einzahlungen (dynamic — works regardless of how many rows exist)
  if (sumEin) {
    const s = emptyMonthly()
    for (const row of liquid) {
      if (row.row_type === 'einzahlung' && row.id !== sumEin.id) {
        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 = ALL auszahlungen (dynamic)
  if (sumAus) {
    const s = emptyMonthly()
    for (const row of liquid) {
      if (row.row_type === 'auszahlung' && row.id !== sumAus.id) {
        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
  }

  // UEBERSCHUSS VOR INVESTITIONEN = Summe ERTRAEGE - Summe AUSZAHLUNGEN (total cashflow)
  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
  }

  // UEBERSCHUSS VOR ENTNAHMEN = UEBERSCHUSS VOR INVESTITIONEN - 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
  }

  // UEBERSCHUSS = UEBERSCHUSS VOR ENTNAHMEN - Kapitalentnahmen
  const entnahmen = findLiqMatch(['Kapitalentnahmen/Ausschüttungen', 'Kapitalentnahmen/Ausschuettungen'])
  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 balance: LIQUIDITAET[m] = LIQUIDITAET[m-1] + UEBERSCHUSS[m]
  // UEBERSCHUSS now includes ALL cash flows (operative + financing + repayments)
  if (kontostand && liquiditaet && ueberschuss) {
    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}`])
      lq[`m${m}`] = Math.round(ks[`m${m}`] + (ueberschuss.values[`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
  }
}
