import { NextRequest, NextResponse } from 'next/server'
import pool from '@/lib/db'
import { computeFinanzplan } from '@/lib/finanzplan/engine'
import { finanzplanToFMResults } from '@/lib/finanzplan/adapter'

export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { scenarioId, source, force } = body

    // If source=finanzplan, use the Finanzplan engine instead
    if (source === 'finanzplan') {
      try {
        // First run the Finanzplan compute engine
        await computeFinanzplan(pool, scenarioId || undefined)
        // Then adapt results to FMResult format
        const result = await finanzplanToFMResults(pool, scenarioId || undefined)
        return NextResponse.json(result)
      } catch (error) {
        console.error('Finanzplan compute error:', error)
        return NextResponse.json({ error: 'Finanzplan computation failed: ' + String(error) }, { status: 500 })
      }
    }

    if (!scenarioId) {
      return NextResponse.json({ error: 'scenarioId is required' }, { status: 400 })
    }

    const client = await pool.connect()
    try {
      // Fast path: return cached results if they exist (skip when force=true)
      const cached = force ? { rows: [] } : await client.query(
        'SELECT * FROM pitch_fm_results WHERE scenario_id = $1 ORDER BY month',
        [scenarioId]
      )
      if (cached.rows.length > 0) {
        const results = cached.rows
        const lastResult = results[results.length - 1]
        const breakEvenMonth = results.find(r => r.month > 1 && (r.revenue_eur - r.total_costs_eur) >= 0)?.month || null
        return NextResponse.json({
          scenario_id: scenarioId,
          results,
          summary: {
            final_arr: lastResult.arr_eur,
            final_customers: lastResult.total_customers,
            break_even_month: breakEvenMonth,
            final_runway: lastResult.runway_months,
            final_ltv_cac: lastResult.ltv_cac_ratio,
            peak_burn: Math.max(...results.map((r: Record<string, number>) => r.burn_rate_eur)),
            total_funding_needed: Math.round(Math.abs(Math.min(...results.map((r: Record<string, number>) => r.cash_balance_eur), 0)) * 100) / 100,
          },
        })
      }

      // Load assumptions
      const assumptionsRes = await client.query(
        'SELECT key, value, value_type FROM pitch_fm_assumptions WHERE scenario_id = $1',
        [scenarioId]
      )

      const a: Record<string, number | number[]> = {}
      for (const row of assumptionsRes.rows) {
        const val = typeof row.value === 'string' ? JSON.parse(row.value) : row.value
        a[row.key] = val
      }

      // Extract scalar values
      const initialFunding = Number(a.initial_funding) || 200000
      const growthRate = (Number(a.monthly_growth_rate) || 15) / 100
      const churnRate = (Number(a.churn_rate_monthly) || 3) / 100
      const arpuMini = Number(a.arpu_mini) || 299
      const arpuStudio = Number(a.arpu_studio) || 999
      const arpuCloud = Number(a.arpu_cloud) || 1499
      const mixMini = (Number(a.product_mix_mini) || 60) / 100
      const mixStudio = (Number(a.product_mix_studio) || 25) / 100
      const mixCloud = (Number(a.product_mix_cloud) || 15) / 100
      const initialCustomers = Number(a.initial_customers) || 2
      const cac = Number(a.cac) || 500
      const hwCostMini = Number(a.hw_cost_per_mini) || 3200
      const hwCostStudio = Number(a.hw_cost_per_studio) || 12000
      const cloudOpex = Number(a.cloud_opex_per_customer) || 150
      const salaryAvg = Number(a.salary_avg_monthly) || 6000
      const hiringPlan: number[] = Array.isArray(a.hiring_plan) ? a.hiring_plan : [2, 4, 8, 12, 18]
      const marketingMonthly = Number(a.marketing_monthly) || 2000
      const infraBase = Number(a.infra_monthly_base) || 500

      // Weighted ARPU
      const weightedArpu = arpuMini * mixMini + arpuStudio * mixStudio + arpuCloud * mixCloud

      // Weighted hardware cost (only for Mini and Studio — Cloud is OpEx)
      const hwCostWeighted = hwCostMini * mixMini + hwCostStudio * mixStudio

      const results = []
      let totalCustomers = initialCustomers
      let cashBalance = initialFunding
      let cumulativeRevenue = 0
      let breakEvenMonth: number | null = null
      let peakBurn = 0

      for (let m = 1; m <= 60; m++) {
        const yearIndex = Math.floor((m - 1) / 12) // 0-4
        const year = 2026 + yearIndex
        const monthInYear = ((m - 1) % 12) + 1

        // Employees from hiring plan
        const employees = hiringPlan[Math.min(yearIndex, hiringPlan.length - 1)] || 2

        // Customer dynamics
        const newCustomers = m === 1 ? initialCustomers : Math.max(1, Math.round(totalCustomers * growthRate))
        const churned = Math.round(totalCustomers * churnRate)
        if (m > 1) {
          totalCustomers = totalCustomers + newCustomers - churned
        }
        totalCustomers = Math.max(0, totalCustomers)

        // Revenue
        const mrr = totalCustomers * weightedArpu
        const arr = mrr * 12
        const revenue = mrr

        // Costs
        const personnelCost = employees * salaryAvg
        const cogsHardware = newCustomers * hwCostWeighted
        const cogsCloud = totalCustomers * mixCloud * cloudOpex
        const cogs = cogsHardware + cogsCloud
        const marketingCost = marketingMonthly + (newCustomers * cac)
        const infraCost = infraBase + (totalCustomers * 5) // infra scales slightly
        const totalCosts = personnelCost + cogs + marketingCost + infraCost

        // Cash
        const netCash = revenue - totalCosts
        cashBalance += netCash
        cumulativeRevenue += revenue

        // KPIs
        const grossMargin = revenue > 0 ? ((revenue - cogs) / revenue) * 100 : 0
        const burnRate = netCash < 0 ? Math.abs(netCash) : 0
        const runway = burnRate > 0 ? cashBalance / burnRate : 999
        const avgLifetimeMonths = churnRate > 0 ? 1 / churnRate : 60
        const ltv = weightedArpu * avgLifetimeMonths
        const ltvCacRatio = cac > 0 ? ltv / cac : 0

        if (peakBurn < burnRate) peakBurn = burnRate

        // Break-even detection
        if (breakEvenMonth === null && netCash >= 0 && m > 1) {
          breakEvenMonth = m
        }

        results.push({
          month: m,
          year,
          month_in_year: monthInYear,
          new_customers: newCustomers,
          churned_customers: churned,
          total_customers: totalCustomers,
          mrr_eur: Math.round(mrr * 100) / 100,
          arr_eur: Math.round(arr * 100) / 100,
          revenue_eur: Math.round(revenue * 100) / 100,
          cogs_eur: Math.round(cogs * 100) / 100,
          personnel_eur: Math.round(personnelCost * 100) / 100,
          infra_eur: Math.round(infraCost * 100) / 100,
          marketing_eur: Math.round(marketingCost * 100) / 100,
          total_costs_eur: Math.round(totalCosts * 100) / 100,
          employees_count: employees,
          gross_margin_pct: Math.round(grossMargin * 100) / 100,
          burn_rate_eur: Math.round(burnRate * 100) / 100,
          runway_months: Math.round(Math.min(runway, 999) * 10) / 10,
          cac_eur: cac,
          ltv_eur: Math.round(ltv * 100) / 100,
          ltv_cac_ratio: Math.round(ltvCacRatio * 100) / 100,
          cash_balance_eur: Math.round(cashBalance * 100) / 100,
          cumulative_revenue_eur: Math.round(cumulativeRevenue * 100) / 100,
        })
      }

      // Save to DB (batch insert — single query instead of 60 individual inserts)
      await client.query('DELETE FROM pitch_fm_results WHERE scenario_id = $1', [scenarioId])
      const cols = 'scenario_id, month, year, month_in_year, new_customers, churned_customers, total_customers, mrr_eur, arr_eur, revenue_eur, cogs_eur, personnel_eur, infra_eur, marketing_eur, total_costs_eur, employees_count, gross_margin_pct, burn_rate_eur, runway_months, cac_eur, ltv_eur, ltv_cac_ratio, cash_balance_eur, cumulative_revenue_eur'
      const values: unknown[] = []
      const placeholders: string[] = []
      results.forEach((r, i) => {
        const offset = i * 24
        placeholders.push(`(${Array.from({length: 24}, (_, j) => `$${offset + j + 1}`).join(',')})`)
        values.push(
          scenarioId, r.month, r.year, r.month_in_year,
          r.new_customers, r.churned_customers, r.total_customers,
          r.mrr_eur, r.arr_eur, r.revenue_eur,
          r.cogs_eur, r.personnel_eur, r.infra_eur, r.marketing_eur, r.total_costs_eur,
          r.employees_count, r.gross_margin_pct, r.burn_rate_eur, r.runway_months,
          r.cac_eur, r.ltv_eur, r.ltv_cac_ratio,
          r.cash_balance_eur, r.cumulative_revenue_eur,
        )
      })
      await client.query(`INSERT INTO pitch_fm_results (${cols}) VALUES ${placeholders.join(',')}`, values)

      const lastResult = results[results.length - 1]
      return NextResponse.json({
        scenario_id: scenarioId,
        results,
        summary: {
          final_arr: lastResult.arr_eur,
          final_customers: lastResult.total_customers,
          break_even_month: breakEvenMonth,
          final_runway: lastResult.runway_months,
          final_ltv_cac: lastResult.ltv_cac_ratio,
          peak_burn: Math.round(peakBurn * 100) / 100,
          total_funding_needed: Math.round(Math.abs(Math.min(...results.map(r => r.cash_balance_eur), 0)) * 100) / 100,
        },
      })
    } finally {
      client.release()
    }
  } catch (error) {
    console.error('Compute error:', error)
    return NextResponse.json({ error: 'Computation failed' }, { status: 500 })
  }
}
