import { NextRequest, NextResponse } from 'next/server'
import pool from '@/lib/db'

interface FundingEvent {
  month: number
  amount: number
  label: string
}

interface SalaryStep {
  from_month: number
  salary: number
}

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

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

    const client = await pool.connect()
    try {
      // 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[] | FundingEvent[] | SalaryStep[]> = {}
      for (const row of assumptionsRes.rows) {
        const val = typeof row.value === 'string' ? JSON.parse(row.value) : row.value
        a[row.key] = val
      }

      // Funding schedule (staged capital injections)
      const fundingSchedule: FundingEvent[] = Array.isArray(a.funding_schedule)
        ? (a.funding_schedule as FundingEvent[])
        : [
            { month: 8, amount: 25000, label: 'Stammkapital GmbH' },
            { month: 9, amount: 25000, label: 'Angel-Runde' },
            { month: 10, amount: 200000, label: 'Wandeldarlehen (Investor + L-Bank)' },
            { month: 19, amount: 1000000, label: 'Series A' },
          ]

      // Founder salary schedule (per founder)
      const founderSalarySchedule: SalaryStep[] = Array.isArray(a.founder_salary_schedule)
        ? (a.founder_salary_schedule as SalaryStep[])
        : [
            { from_month: 1, salary: 0 },
            { from_month: 10, salary: 3000 },
            { from_month: 13, salary: 6000 },
            { from_month: 25, salary: 10000 },
          ]

      const numFounders = Number(a.num_founders) || 2

      // Extract scalar values
      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
      // Hiring plan: employees EXCLUDING founders (hired staff only)
      const hiringPlan: number[] = Array.isArray(a.hiring_plan) ? (a.hiring_plan as number[]) : [0, 1, 3, 6, 10]
      const marketingMonthly = Number(a.marketing_monthly) || 2000
      const infraBase = Number(a.infra_monthly_base) || 500

      // Detail cost assumptions
      const ihkAnnual = Number(a.ihk_annual) || 180
      const phoneInternetMonthly = Number(a.phone_internet_monthly) || 100
      const taxAdvisorMonthly = Number(a.tax_advisor_monthly) || 300
      const notaryFounding = Number(a.notary_founding) || 2500
      const insuranceMonthly = Number(a.insurance_monthly) || 200
      const officeRentMonthly = Number(a.office_rent_monthly) || 0
      const softwareLicensesMonthly = Number(a.software_licenses_monthly) || 150
      const travelMonthly = Number(a.travel_monthly) || 200
      const legalMonthly = Number(a.legal_monthly) || 100
      const depreciationRatePct = Number(a.depreciation_rate_pct) || 33
      const taxRatePct = Number(a.tax_rate_pct) || 30
      const interestRatePct = Number(a.interest_rate_pct) || 5
      // Hardware financing: only this % paid upfront, rest via leasing/financing
      const hwUpfrontPct = (Number(a.hw_upfront_pct) || 30) / 100

      // GmbH founding month (month 8 = August 2026)
      const gmbhFoundingMonth = 8

      // 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

      // Helper: get founder salary for a given month
      function getFounderSalary(month: number): number {
        let salary = 0
        for (const step of founderSalarySchedule) {
          if (month >= step.from_month) {
            salary = step.salary
          }
        }
        return salary
      }

      // Helper: get funding for a given month
      function getFundingForMonth(month: number): number {
        let total = 0
        for (const event of fundingSchedule) {
          if (event.month === month) {
            total += event.amount
          }
        }
        return total
      }

      const results = []
      let totalCustomers = 0
      let cashBalance = 0 // Start at 0, funding comes via schedule
      let cumulativeRevenue = 0
      let breakEvenMonth: number | null = null
      let peakBurn = 0
      let cumulativeHwInvestment = 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

        // === FUNDING: Add capital injection for this month ===
        const fundingThisMonth = getFundingForMonth(m)
        cashBalance += fundingThisMonth

        // === PRE-GMBH PHASE (months 1-7): No costs, private development ===
        if (m < gmbhFoundingMonth) {
          results.push({
            month: m,
            year,
            month_in_year: monthInYear,
            new_customers: 0,
            churned_customers: 0,
            total_customers: 0,
            mrr_eur: 0,
            arr_eur: 0,
            revenue_eur: 0,
            cogs_eur: 0,
            personnel_eur: 0,
            infra_eur: 0,
            marketing_eur: 0,
            total_costs_eur: 0,
            employees_count: 0,
            gross_margin_pct: 0,
            burn_rate_eur: 0,
            runway_months: 999,
            cac_eur: 0,
            ltv_eur: 0,
            ltv_cac_ratio: 0,
            cash_balance_eur: Math.round(cashBalance * 100) / 100,
            cumulative_revenue_eur: 0,
            admin_costs_eur: 0,
            office_costs_eur: 0,
            founding_costs_eur: 0,
            ihk_eur: 0,
            depreciation_eur: 0,
            interest_expense_eur: 0,
            taxes_eur: 0,
            net_income_eur: 0,
            ebit_eur: 0,
            software_licenses_eur: 0,
            travel_costs_eur: 0,
            funding_eur: fundingThisMonth,
          })
          continue
        }

        // === POST-GMBH PHASE (months 8+): Real business operations ===

        // Hired employees: plan-based but capped by revenue (don't hire ahead of revenue)
        const plannedHires = hiringPlan[Math.min(yearIndex, hiringPlan.length - 1)] || 0
        const revenueBasedMaxHires = Math.floor((totalCustomers * weightedArpu) / salaryAvg)
        const hiredEmployees = Math.min(plannedHires, Math.max(0, revenueBasedMaxHires))

        // Founder salary
        const founderSalaryPerPerson = getFounderSalary(m)
        const totalFounderSalary = founderSalaryPerPerson * numFounders

        // Total employees shown (founders + hired)
        const totalEmployees = numFounders + hiredEmployees

        // Customer dynamics — start acquiring customers from GmbH founding
        const monthsSinceGmbh = m - gmbhFoundingMonth + 1
        if (monthsSinceGmbh === 1) {
          totalCustomers = initialCustomers
        }

        let newCustomers = monthsSinceGmbh === 1
          ? initialCustomers
          : Math.max(1, Math.round(totalCustomers * growthRate))

        // Cash constraint: don't spend more than available
        // Fixed OPEX this month (independent of new customer count)
        const fixedOpex = (totalFounderSalary + hiredEmployees * salaryAvg)
          + marketingMonthly
          + infraBase + (totalCustomers * 5)
          + (totalCustomers * mixCloud * cloudOpex)
          + phoneInternetMonthly + taxAdvisorMonthly + insuranceMonthly + legalMonthly
          + officeRentMonthly + (m === gmbhFoundingMonth ? notaryFounding : 0)
          + ihkAnnual / 12 + softwareLicensesMonthly + travelMonthly
        const estRevenue = totalCustomers * weightedArpu
        // Available cash = current balance + this month's revenue - fixed costs
        const availableCash = cashBalance + estRevenue - fixedOpex
        // Variable cost per new customer: hardware CAPEX (upfront portion) + CAC
        const varCostPerNew = hwCostWeighted * hwUpfrontPct + cac
        // Max affordable new customers (keep cash >= 0)
        if (varCostPerNew > 0 && monthsSinceGmbh > 1) {
          const maxAffordable = Math.floor(availableCash / varCostPerNew)
          newCustomers = Math.min(newCustomers, Math.max(1, maxAffordable))
        }

        const churned = Math.round(totalCustomers * churnRate)
        if (monthsSinceGmbh > 1) {
          totalCustomers = totalCustomers + newCustomers - churned
        }
        totalCustomers = Math.max(0, totalCustomers)

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

        // Costs
        const hiredPersonnelCost = hiredEmployees * salaryAvg
        const personnelCost = totalFounderSalary + hiredPersonnelCost

        // Hardware = CAPEX (only upfront portion paid from cash, rest financed)
        const capexHardware = newCustomers * hwCostWeighted * hwUpfrontPct
        // Cloud OPEX + hardware leasing cost (financed portion amortized over 36 months)
        const cogsCloud = totalCustomers * mixCloud * cloudOpex
        const hwLeasingMonthly = (cumulativeHwInvestment * (1 - hwUpfrontPct)) / 36
        const cogs = cogsCloud + hwLeasingMonthly
        const marketingCost = marketingMonthly + (newCustomers * cac)
        const infraCost = infraBase + (totalCustomers * 5)

        // Detail costs
        const adminCosts = phoneInternetMonthly + taxAdvisorMonthly + insuranceMonthly + legalMonthly
        const officeCosts = officeRentMonthly
        // Founding costs: notary in month 8 (GmbH founding)
        const foundingCosts = m === gmbhFoundingMonth ? notaryFounding : 0
        const ihkMonthly = ihkAnnual / 12
        const softwareLicenses = softwareLicensesMonthly
        const travelCosts = travelMonthly

        // Depreciation: cumulative HW investment * rate / 12 (P&L expense for CAPEX)
        cumulativeHwInvestment += capexHardware
        const depreciationMonthly = (cumulativeHwInvestment * depreciationRatePct / 100) / 12

        // Total OPEX (P&L) — hardware enters only via depreciation
        const totalCosts = personnelCost + cogs + marketingCost + infraCost
          + adminCosts + officeCosts + foundingCosts + ihkMonthly
          + softwareLicenses + travelCosts + depreciationMonthly

        // EBIT
        const ebit = revenue - totalCosts

        // Interest expense (only if cash balance is negative)
        const interestExpense = cashBalance < 0 ? Math.abs(cashBalance) * interestRatePct / 100 / 12 : 0

        // Taxes (only if profit positive)
        const ebt = ebit - interestExpense
        const taxes = ebt > 0 ? ebt * taxRatePct / 100 : 0

        // Net income
        const netIncome = ebt - taxes

        // Cash: net income MINUS hardware CAPEX (funding already added at top)
        cashBalance += netIncome - capexHardware
        cumulativeRevenue += revenue

        // KPIs — gross margin uses COGS + depreciation for true margin
        const grossMargin = revenue > 0 ? ((revenue - cogs - depreciationMonthly) / revenue) * 100 : 0
        const burnRate = (netIncome - capexHardware) < 0 ? Math.abs(netIncome - capexHardware) : 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 && netIncome >= 0 && m > gmbhFoundingMonth) {
          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: totalEmployees,
          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,
          // Detail costs
          admin_costs_eur: Math.round(adminCosts * 100) / 100,
          office_costs_eur: Math.round(officeCosts * 100) / 100,
          founding_costs_eur: Math.round(foundingCosts * 100) / 100,
          ihk_eur: Math.round(ihkMonthly * 100) / 100,
          depreciation_eur: Math.round(depreciationMonthly * 100) / 100,
          interest_expense_eur: Math.round(interestExpense * 100) / 100,
          taxes_eur: Math.round(taxes * 100) / 100,
          net_income_eur: Math.round(netIncome * 100) / 100,
          ebit_eur: Math.round(ebit * 100) / 100,
          software_licenses_eur: Math.round(softwareLicenses * 100) / 100,
          travel_costs_eur: Math.round(travelCosts * 100) / 100,
          funding_eur: fundingThisMonth,
        })
      }

      // Save to DB (upsert) — only columns that exist in the table
      await client.query('DELETE FROM pitch_fm_results WHERE scenario_id = $1', [scenarioId])
      for (const r of results) {
        await client.query(`
          INSERT INTO pitch_fm_results (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)
          VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24)
        `, [
          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,
        ])
      }

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