/**
 * Hype Cycle Data Enrichment — Real metrics from scraped data
 *
 * Computes PhaseMetrics overrides from actual database observations:
 * - vendorCount: How many vendors sell this speed class
 * - price trends: ASP decline rate from price_observations
 * - catalog density: Number of SKUs per speed class (market maturity signal)
 * - product diversity: Form factor and reach variety
 */
import { pool } from "../db/client";
import type { PhaseMetrics } from "./norton-bass";

interface SpeedClassMetrics {
  speedGbps: number;
  vendorCount: number;
  skuCount: number;
  avgPrice?: number;
  minPrice?: number;
  maxPrice?: number;
  priceCount: number;
  formFactors: string[];
  reachVariants: number;
}

/**
 * Query real vendor/product counts per speed class from the database.
 */
export async function getSpeedClassMetrics(): Promise<ReadonlyArray<SpeedClassMetrics>> {
  const result = await pool.query(`
    SELECT
      t.speed_gbps,
      COUNT(DISTINCT t.vendor_id) AS vendor_count,
      COUNT(DISTINCT t.id) AS sku_count,
      ARRAY_AGG(DISTINCT t.form_factor) FILTER (WHERE t.form_factor IS NOT NULL AND t.form_factor != '') AS form_factors,
      COUNT(DISTINCT t.reach_label) FILTER (WHERE t.reach_label IS NOT NULL AND t.reach_label != '') AS reach_variants
    FROM transceivers t
    WHERE t.speed_gbps > 0
    GROUP BY t.speed_gbps
    ORDER BY t.speed_gbps
  `);

  const priceResult = await pool.query(`
    SELECT
      t.speed_gbps,
      AVG(po.price) AS avg_price,
      MIN(po.price) AS min_price,
      MAX(po.price) AS max_price,
      COUNT(*) AS price_count
    FROM price_observations po
    JOIN transceivers t ON t.id = po.transceiver_id
    WHERE t.speed_gbps > 0
    GROUP BY t.speed_gbps
  `);

  const priceMap = new Map<number, { avg: number; min: number; max: number; count: number }>();
  for (const row of priceResult.rows) {
    priceMap.set(Number(row.speed_gbps), {
      avg: parseFloat(row.avg_price),
      min: parseFloat(row.min_price),
      max: parseFloat(row.max_price),
      count: parseInt(row.price_count),
    });
  }

  return result.rows.map((row) => {
    const speedGbps = Number(row.speed_gbps);
    const priceData = priceMap.get(speedGbps);
    return {
      speedGbps,
      vendorCount: parseInt(row.vendor_count),
      skuCount: parseInt(row.sku_count),
      avgPrice: priceData?.avg,
      minPrice: priceData?.min,
      maxPrice: priceData?.max,
      priceCount: priceData?.count ?? 0,
      formFactors: row.form_factors || [],
      reachVariants: parseInt(row.reach_variants),
    };
  });
}

/**
 * Convert raw speed-class metrics into PhaseMetrics overrides.
 * These override the model-estimated values with real data.
 */
export function metricsToPhaseOverrides(
  metrics: SpeedClassMetrics,
  totalMarketSkus: number,
): { -readonly [K in keyof PhaseMetrics]?: PhaseMetrics[K] } {
  const overrides: { -readonly [K in keyof PhaseMetrics]?: PhaseMetrics[K] } = {};

  // Vendor count — direct from data
  overrides.vendorCount = metrics.vendorCount;

  // Vendor trend — estimate from catalog density
  // More SKUs + more vendors = increasing; few = decreasing
  if (metrics.vendorCount >= 4 && metrics.skuCount > 50) {
    overrides.vendorTrend = "stable";
  } else if (metrics.vendorCount >= 2) {
    overrides.vendorTrend = "increasing";
  } else {
    overrides.vendorTrend = "decreasing";
  }

  // Shipment share proxy — SKU count relative to total market
  overrides.shipmentShare = Math.min(0.5, metrics.skuCount / Math.max(1, totalMarketSkus));

  // Interop level — more reach variants and form factors = better interop
  const ffDiversity = metrics.formFactors.length;
  const reachDiversity = metrics.reachVariants;
  overrides.interopLevel = Math.min(100, ffDiversity * 15 + reachDiversity * 8);

  return overrides;
}

/**
 * Get enriched PhaseMetrics for all speed classes.
 * Returns a map of speedGbps -> partial PhaseMetrics overrides.
 */
export async function getDataDrivenOverrides(): Promise<Map<number, { -readonly [K in keyof PhaseMetrics]?: PhaseMetrics[K] }>> {
  const allMetrics = await getSpeedClassMetrics();
  const totalSkus = allMetrics.reduce((sum, m) => sum + m.skuCount, 0);

  const overridesMap = new Map<number, { -readonly [K in keyof PhaseMetrics]?: PhaseMetrics[K] }>();
  for (const metrics of allMetrics) {
    overridesMap.set(metrics.speedGbps, metricsToPhaseOverrides(metrics, totalSkus));
  }

  return overridesMap;
}

/**
 * Revenue lifecycle prediction per speed class.
 *
 * Uses scraped price data + Bass diffusion to estimate:
 * - Peak revenue year
 * - Revenue duration (years above 50% of peak)
 * - Current revenue trajectory
 */
export interface RevenueLifecycle {
  speedGbps: number;
  technology: string;
  currentAvgPrice?: number;
  estimatedPeakRevenueYear: number;
  estimatedDeclineStartYear: number;
  revenueHalfLifeYears: number;
  currentPhase: "growing" | "peaking" | "declining" | "legacy";
  revenueIndex: number; // 0-100, relative to estimated peak
}

export function computeRevenueLifecycle(
  speedGbps: number,
  techName: string,
  introYear: number,
  peakYear: number,
  currentYear: number,
  avgPrice?: number,
): RevenueLifecycle {
  // Revenue = Price × Volume. Price declines while volume grows.
  // Peak revenue happens ~2 years before peak volume (when price×volume is maximized)
  const peakRevenueYear = Math.round(peakYear - 2);
  const declineStartYear = peakYear + 2;
  const halfLife = Math.round((peakYear - introYear) * 0.7);

  const yearsFromPeak = currentYear - peakRevenueYear;
  let currentPhase: RevenueLifecycle["currentPhase"];
  if (currentYear < peakRevenueYear - 2) currentPhase = "growing";
  else if (currentYear <= peakRevenueYear + 2) currentPhase = "peaking";
  else if (currentYear <= declineStartYear + halfLife) currentPhase = "declining";
  else currentPhase = "legacy";

  // Revenue index: bell curve centered on peakRevenueYear
  const sigma = halfLife / 1.5;
  const revenueIndex = Math.round(100 * Math.exp(-0.5 * Math.pow(yearsFromPeak / sigma, 2)));

  return {
    speedGbps,
    technology: techName,
    currentAvgPrice: avgPrice,
    estimatedPeakRevenueYear: peakRevenueYear,
    estimatedDeclineStartYear: declineStartYear,
    revenueHalfLifeYears: halfLife,
    currentPhase,
    revenueIndex,
  };
}

/**
 * Regional adoption model.
 * Applies lag coefficients per region based on industry research.
 */
export interface RegionalAdoption {
  region: string;
  lagYears: number;
  marketSharePct: number;
  adoptionPhase: string;
  estimatedPeakYear: number;
}

/**
 * Regional lag coefficients calibrated from research (2026-03-28).
 * Sources: LightCounting, vendor earnings, OFC market sessions, Chinese IPO prospectuses.
 * Lag in years (converted from quarters: NA=0, CN=0.5Q≈0.125yr, EU=4Q=1yr, etc.)
 */
const REGIONAL_LAGS: ReadonlyArray<{
  region: string;
  lagYears: number;
  marketSharePct: number;
  priceIndex: number;
  segmentMix: { hyperscaler: number; telco: number; enterprise: number };
}> = [
  {
    region: "North America (Hyperscale)",
    lagYears: 0,
    marketSharePct: 32,
    priceIndex: 1.0,
    segmentMix: { hyperscaler: 0.65, telco: 0.20, enterprise: 0.15 },
  },
  {
    region: "China (BAT/Hyperscale)",
    lagYears: 0.125,  // 0.5 quarters = near-parity, sometimes leads on volume
    marketSharePct: 38,
    priceIndex: 0.58,  // 42% cheaper domestically
    segmentMix: { hyperscaler: 0.50, telco: 0.35, enterprise: 0.15 },
  },
  {
    region: "APAC (ex-China)",
    lagYears: 0.625,  // 2.5 quarters
    marketSharePct: 13,
    priceIndex: 1.0,
    segmentMix: { hyperscaler: 0.35, telco: 0.40, enterprise: 0.25 },
  },
  {
    region: "Europe",
    lagYears: 1.0,    // 4 quarters — telco procurement cycles, regulatory compliance
    marketSharePct: 14,
    priceIndex: 1.12,  // 12% premium (CE/RoHS compliance, smaller volumes, channel markup)
    segmentMix: { hyperscaler: 0.25, telco: 0.45, enterprise: 0.30 },
  },
  {
    region: "Rest of World",
    lagYears: 1.5,    // 6 quarters
    marketSharePct: 3,
    priceIndex: 1.05,
    segmentMix: { hyperscaler: 0.20, telco: 0.50, enterprise: 0.30 },
  },
];

export function computeRegionalAdoption(
  techPeakYear: number,
  currentYear: number,
  techName: string,
): ReadonlyArray<RegionalAdoption> {
  return REGIONAL_LAGS.map(({ region, lagYears, marketSharePct }) => {
    const regionalPeak = techPeakYear + lagYears;
    const yearsToPeak = regionalPeak - currentYear;

    let adoptionPhase: string;
    if (yearsToPeak > 5) adoptionPhase = "Pre-adoption";
    else if (yearsToPeak > 2) adoptionPhase = "Early Adoption";
    else if (yearsToPeak > -1) adoptionPhase = "Growth";
    else if (yearsToPeak > -4) adoptionPhase = "Mature";
    else adoptionPhase = "Declining";

    return {
      region,
      lagYears,
      marketSharePct,
      adoptionPhase,
      estimatedPeakYear: Math.round(regionalPeak * 2) / 2, // Round to half-year
    };
  });
}
