/**
 * WS5 + WS6: Sales Forecast Engine + Price Trajectory
 */
import { Router } from "express";
import { pool } from "../db/client";
import { computeHypeCycle, findTechnology, TECH_GENERATIONS } from "../hype-cycle/norton-bass";

export const forecastRouter = Router();

/**
 * GET /api/forecast/:technology
 *
 * Returns sales forecast for 3/9/12/18 months + price trajectory + buy signal
 */
forecastRouter.get("/:technology", async (req, res) => {
  try {
    const techQuery = req.params.technology;
    const currentYear = new Date().getFullYear();

    // Find technology in Norton-Bass model
    const tech = findTechnology(techQuery);
    if (!tech) {
      return res.status(404).json({
        error: "Technology not found",
        available: TECH_GENERATIONS.map(t => t.name),
      });
    }

    // Compute hype cycle
    const hype = computeHypeCycle(tech, currentYear);

    // Get price data from DB
    const priceHistory = await pool.query(`
      SELECT
        date_trunc('week', po.time) AS week,
        AVG(po.price) AS avg_price,
        MIN(po.price) AS min_price,
        MAX(po.price) AS max_price,
        COUNT(*) AS observations,
        po.currency
      FROM price_observations po
      JOIN transceivers t ON po.transceiver_id = t.id
      WHERE t.speed_gbps = $1
      GROUP BY week, po.currency
      ORDER BY week DESC
      LIMIT 52
    `, [tech.speedGbps]);

    // Compute price trajectory based on hype cycle phase
    const currentPrices = priceHistory.rows.length > 0
      ? priceHistory.rows.map(r => parseFloat(r.avg_price))
      : [];
    const currentASP = currentPrices.length > 0 ? currentPrices[0]! : tech.speedGbps * 0.5; // rough estimate

    // Price decline model based on phase
    const phaseDeclineRates: Record<string, number> = {
      'INNOVATION_TRIGGER': 0.05,
      'PEAK_OF_INFLATED_EXPECTATIONS': 0.12,
      'TROUGH_OF_DISILLUSIONMENT': 0.25,
      'SLOPE_OF_ENLIGHTENMENT': 0.15,
      'PLATEAU_OF_PRODUCTIVITY': 0.05,
      'LEGACY_DECLINE': 0.03,
    };
    const annualDecline = phaseDeclineRates[hype.phase] ?? 0.10;
    const monthlyDecline = 1 - Math.pow(1 - annualDecline, 1/12);

    const asp3m = currentASP * Math.pow(1 - monthlyDecline, 3);
    const asp9m = currentASP * Math.pow(1 - monthlyDecline, 9);
    const asp12m = currentASP * Math.pow(1 - monthlyDecline, 12);
    const asp18m = currentASP * Math.pow(1 - monthlyDecline, 18);

    // Price floor estimate (based on mature technology pricing patterns)
    // Typically 15-25% of peak price at full maturity
    const priceFloor = currentASP * 0.20;
    const monthsToFloor = annualDecline > 0
      ? Math.ceil(Math.log(priceFloor / currentASP) / Math.log(1 - monthlyDecline))
      : 999;

    // Volume forecast based on adoption curve
    const adoptionNow = hype.adoptionPct / 100;
    const proj = hype.forecast.fiveYearProjection;
    const adoption3m = Math.min(1, adoptionNow + (proj?.[0]?.adoptionPct ?? 0) / 100 * 0.25);
    const adoption9m = Math.min(1, adoptionNow + (proj?.[0]?.adoptionPct ?? 0) / 100 * 0.75);
    const adoption12m = Math.min(1, adoptionNow + (proj?.[1]?.adoptionPct ?? 0) / 100);
    const adoption18m = Math.min(1, adoptionNow + (proj?.[2]?.adoptionPct ?? 0) / 100);

    // Volume forecast — calibrated with real Flexoptix demand data where available
    const demandCalib = await pool.query(`
      SELECT
        ROUND(SUM(d.demand_12m))  AS units_per_month_12m,
        ROUND(SUM(d.demand_3m))   AS units_per_month_3m,
        CASE WHEN SUM(d.demand_12m) > 0
             THEN SUM(d.demand_3m) / SUM(d.demand_12m)
             ELSE 1 END           AS growth_factor
      FROM flexoptix_internal_demand d
      JOIN transceivers t ON t.id = d.transceiver_id
      WHERE t.speed_gbps = $1
        AND (d.demand_12m > 0 OR d.demand_3m > 0)
    `, [tech.speedGbps]).catch(() => ({ rows: [] as Array<Record<string, string>> }));

    const realDemand = demandCalib.rows[0] as Record<string, string> | undefined;
    const hasRealData = realDemand && parseFloat(realDemand["units_per_month_12m"] ?? "0") > 0;

    let units3m: number;
    let units9m: number;
    let units12m: number;
    let units18m: number;

    if (hasRealData && realDemand) {
      // Real Flexoptix run-rates scaled by adoption momentum
      const monthly12m = parseFloat(realDemand["units_per_month_12m"]!);
      const monthly3m  = parseFloat(realDemand["units_per_month_3m"]!);
      const growthFactor = Math.max(0.5, Math.min(2.0, parseFloat(realDemand["growth_factor"] ?? "1")));

      units3m  = Math.round(monthly3m * 3);
      units9m  = Math.round(monthly3m * 9 * Math.pow(growthFactor, 0.5));
      units12m = Math.round(monthly12m * 12 * growthFactor);
      units18m = Math.round(monthly12m * 18 * Math.pow(growthFactor, 1.2));
    } else {
      // Fallback: Norton-Bass model-based estimate
      const totalMarketPorts = tech.m * 1000000;
      const marketShare = 0.03;
      units3m  = Math.round(totalMarketPorts * adoption3m  * marketShare * 0.25);
      units9m  = Math.round(totalMarketPorts * adoption9m  * marketShare * 0.75);
      units12m = Math.round(totalMarketPorts * adoption12m * marketShare);
      units18m = Math.round(totalMarketPorts * adoption18m * marketShare * 1.5);
    }

    // Confidence decreases with forecast horizon
    const conf3m = Math.min(0.95, 0.85 + (priceHistory.rows.length / 100));
    const conf9m = conf3m * 0.78;
    const conf12m = conf3m * 0.65;
    const conf18m = conf3m * 0.50;

    // Buy signal
    let buySignal: string;
    let signalReason: string;
    if (hype.phase === 'SLOPE_OF_ENLIGHTENMENT' || hype.phase === 'PLATEAU_OF_PRODUCTIVITY') {
      buySignal = 'BUY_NOW';
      signalReason = `${tech.name} is in ${hype.phase.replace(/_/g, ' ').toLowerCase()} — prices near floor, volume growing, stable supply chain.`;
    } else if (hype.phase === 'TROUGH_OF_DISILLUSIONMENT') {
      buySignal = 'WAIT';
      signalReason = `${tech.name} prices dropping >10%/quarter. Wait for trough bottom (estimated ${Math.ceil(monthsToFloor * 0.3)} months).`;
    } else if (hype.phase === 'PEAK_OF_INFLATED_EXPECTATIONS') {
      buySignal = 'WAIT';
      signalReason = `${tech.name} is at peak hype — prices will drop significantly. Only buy if urgent.`;
    } else if (hype.phase === 'INNOVATION_TRIGGER') {
      buySignal = 'HOLD';
      signalReason = `${tech.name} is early-stage — limited availability, premium pricing. Wait unless you need bleeding-edge.`;
    } else {
      buySignal = 'HOLD';
      signalReason = `${tech.name} is in legacy/decline — consider migrating to next generation.`;
    }

    // Store forecast in DB
    await pool.query(`
      INSERT INTO sales_forecasts (
        technology, speed_gbps, form_factor,
        forecast_3m_units, forecast_3m_revenue, forecast_9m_units, forecast_9m_revenue,
        forecast_12m_units, forecast_12m_revenue, forecast_18m_units, forecast_18m_revenue,
        current_asp, asp_3m, asp_12m, price_floor, months_to_floor,
        confidence_3m, confidence_9m, confidence_12m, confidence_18m,
        buy_signal, signal_reason, data_points
      ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23)
    `, [
      tech.name, tech.speedGbps, tech.formFactor,
      units3m, units3m * asp3m, units9m, units9m * asp9m,
      units12m, units12m * asp12m, units18m, units18m * asp18m,
      currentASP, asp3m, asp12m, priceFloor, monthsToFloor,
      conf3m, conf9m, conf12m, conf18m,
      buySignal, signalReason, priceHistory.rows.length,
    ]).catch(() => {}); // Non-critical

    res.json({
      technology: tech.name,
      speed_gbps: tech.speedGbps,
      form_factor: tech.formFactor,
      hype_cycle: {
        phase: hype.phase,
        position_pct: hype.positionPct,
        adoption_pct: hype.adoptionPct,
      },
      forecasts: {
        "3_months": { units: units3m, revenue_eur: Math.round(units3m * asp3m), confidence: Math.round(conf3m * 100) / 100 },
        "9_months": { units: units9m, revenue_eur: Math.round(units9m * asp9m), confidence: Math.round(conf9m * 100) / 100 },
        "12_months": { units: units12m, revenue_eur: Math.round(units12m * asp12m), confidence: Math.round(conf12m * 100) / 100 },
        "18_months": { units: units18m, revenue_eur: Math.round(units18m * asp18m), confidence: Math.round(conf18m * 100) / 100 },
      },
      price_trajectory: {
        current_asp: Math.round(currentASP * 100) / 100,
        asp_3m: Math.round(asp3m * 100) / 100,
        asp_9m: Math.round(asp9m * 100) / 100,
        asp_12m: Math.round(asp12m * 100) / 100,
        asp_18m: Math.round(asp18m * 100) / 100,
        price_floor: Math.round(priceFloor * 100) / 100,
        months_to_floor: Math.max(0, monthsToFloor),
        annual_decline_pct: Math.round(annualDecline * 100),
      },
      buy_signal: {
        signal: buySignal,
        reason: signalReason,
      },
      price_history: priceHistory.rows.slice(0, 12),
      model: "Norton-Bass Multigenerational Diffusion v1",
      demand_calibrated: hasRealData ?? false,
    });
  } catch (err) {
    console.error("Forecast error:", err);
    res.status(500).json({ error: "Internal server error" });
  }
});

/**
 * GET /api/forecast
 *
 * Overview of all technology forecasts
 */
forecastRouter.get("/", async (_req, res) => {
  try {
    const currentYear = new Date().getFullYear();
    const results = TECH_GENERATIONS.map(tech => {
      const hype = computeHypeCycle(tech, currentYear);
      return {
        technology: tech.name,
        speed_gbps: tech.speedGbps,
        form_factor: tech.formFactor,
        phase: hype.phase,
        adoption_pct: hype.adoptionPct,
        position_pct: hype.positionPct,
      };
    });

    res.json({ technologies: results });
  } catch (err) {
    res.status(500).json({ error: "Internal server error" });
  }
});
