// data.jsx — bootstrap-seeds + datalaag.
//
// ▸ De RAW/LIBRARY-seeds leveren alleen BOOTSTRAP: ticker, naam, beurs, valuta,
//   defaultLens, normalPE en de waarderingsaannames (`inp`). Hun numerieke
//   marktvelden zijn historisch en worden ALTIJD overschreven door live data
//   (via /api/fundamentals) of op null gezet — nooit als mock getoond.
// ▸ Alle marktcijfers + echte koers-/dividendhistorie komen live van Yahoo
//   (zie lib/yahoo.js + api/fundamentals.js). Ontbreekt data → "Niet beschikbaar".

// Veilige getalconversie: geeft null bij niet-eindig (zodat de UI "Niet
// beschikbaar" toont i.p.v. NaN/0/mock).
function numD(v) { return (Number.isFinite(Number(v)) && v !== null && v !== undefined) ? Number(v) : null; }

// Groei-default voor de waardering. Yahoo's analistenconsensus (`earningsTrend
// +1y`) is een ÉÉNJAARSgetal — ruisig rond cyclische dalen/pieken en eenmalige
// posten — terwijl DCF, Lynch en Graham een langjarige groei verwachten. Krimp
// hem daarom half naar een langjarig basisniveau en begrens op [0, 15%].
const LT_BASE_GROWTH = 0.06;
function defaultGrowth(analystGrowth, fallback) {
  const ag = numD(analystGrowth);
  if (ag == null) return fallback;
  return Math.max(0, Math.min(0.15, 0.5 * ag + 0.5 * LT_BASE_GROWTH));
}
// Groei van een seed: een expliciete AI-schatting (5-jaarsgemiddelde, zie
// buildStock) wint; anders de gekrompen analistenconsensus; anders de seed-aanname.
function seedGrowth(inp, analystGrowth) {
  if (inp && inp.growthSource === 'ai' && Number.isFinite(inp.growth)) return inp.growth;
  return defaultGrowth(analystGrowth, (inp && inp.growth) ?? 0);
}

// FastGraphs-stijl reële-waardeband: snij op de jaren met ZOWEL echte koers als
// echte WPA, bereken de normale K/W als historische mediaan-P/E en de band als
// WPA × normale K/W. Zonder (voldoende) WPA → alleen de koerslijn (geen band).
function buildFairHistory(priceHistory, epsHistory, fallbackPE) {
  const priceByYear = {};
  for (const p of (priceHistory || [])) { const v = numD(p.price); if (v != null) priceByYear[p.year] = v; }
  const epsByYear = {};
  for (const e of (epsHistory || [])) { const v = numD(e.eps); if (v != null) epsByYear[e.year] = v; }
  const years = Object.keys(epsByYear).map(Number).filter((y) => priceByYear[y] != null).sort((a, b) => a - b);

  let normalPE = numD(fallbackPE);
  const pes = years.map((y) => priceByYear[y] / epsByYear[y]).filter((x) => x > 0);
  if (pes.length >= 3) normalPE = median(pes);   // median uit valuations.jsx

  if (years.length >= 2) {
    const history = years.map((y) => ({
      year: y, price: priceByYear[y], eps: epsByYear[y],
      fair: normalPE != null ? +(epsByYear[y] * normalPE).toFixed(2) : null,
    }));
    return { history, normalPE, hasEps: true };
  }
  // geen WPA-reeks → alleen koerslijn over de volledige historie, geen band
  const history = (priceHistory || []).map((p) => ({ year: p.year, price: numD(p.price), eps: null, fair: null }));
  return { history, normalPE, hasEps: false };
}

const RAW = [
  {
    ticker: 'VPK', name: 'Koninklijke Vopak', exchange: 'AMS', currency: 'EUR', sector: 'Tankopslag',
    price: 44.20, dayChange: 0.006, eps: 4.60, peTTM: 9.6, forwardPE: 9.0, peg: 1.6,
    dividendRate: 1.55, dividendYield: 0.035, payoutRatio: 0.34,
    low52: 36.10, high52: 47.80, marketCap: 5.30e9, beta: 0.75, fcf: 480e6, shares: 120e6,
    normalPE: 11, priceCAGR: 0.06, epsCAGR: 0.07, seed: 3, divCAGR: 0.05, divSince: null,
    defaultLens: 'dividend',
    inp: { requiredYield: 0.048, divGrowth: 0.02, growth: 0.05, growthCap: 0.10,
           discountRate: 0.085, terminalGrowth: 0.025, bondYield: 4.8 },
  },
  {
    ticker: 'NN', name: 'NN Group', exchange: 'AMS', currency: 'EUR', sector: 'Verzekeringen',
    price: 47.80, dayChange: -0.004, eps: 5.90, peTTM: 8.1, forwardPE: 7.6, peg: 1.4,
    dividendRate: 3.30, dividendYield: 0.069, payoutRatio: 0.56,
    low52: 38.50, high52: 50.20, marketCap: 13.5e9, beta: 0.90, fcf: 1.6e9, shares: 282e6,
    normalPE: 9, priceCAGR: 0.055, epsCAGR: 0.05, seed: 7, divCAGR: 0.07, divSince: null,
    defaultLens: 'dividend',
    inp: { requiredYield: 0.075, divGrowth: 0.03, growth: 0.04, growthCap: 0.08,
           discountRate: 0.090, terminalGrowth: 0.025, bondYield: 4.8 },
  },
  {
    ticker: 'ASRNL', name: 'ASR Nederland', exchange: 'AMS', currency: 'EUR', sector: 'Verzekeringen',
    price: 51.40, dayChange: 0.011, eps: 5.70, peTTM: 9.0, forwardPE: 8.3, peg: 1.5,
    dividendRate: 3.10, dividendYield: 0.060, payoutRatio: 0.54,
    low52: 42.80, high52: 54.60, marketCap: 8.10e9, beta: 0.85, fcf: 900e6, shares: 158e6,
    normalPE: 10, priceCAGR: 0.07, epsCAGR: 0.06, seed: 11, divCAGR: 0.06, divSince: 2017,
    defaultLens: 'dividend',
    inp: { requiredYield: 0.075, divGrowth: 0.025, growth: 0.045, growthCap: 0.09,
           discountRate: 0.090, terminalGrowth: 0.025, bondYield: 4.8 },
  },
  {
    ticker: 'ASML', name: 'ASML Holding', exchange: 'AMS', currency: 'EUR', sector: 'Halfgeleiders',
    price: 685.00, dayChange: 0.014, eps: 21.50, peTTM: 31.9, forwardPE: 27.5, peg: 1.4,
    dividendRate: 6.40, dividendYield: 0.0093, payoutRatio: 0.30,
    low52: 520.00, high52: 760.00, marketCap: 270e9, beta: 1.25, fcf: 8.0e9, shares: 394e6,
    normalPE: 30, priceCAGR: 0.19, epsCAGR: 0.17, seed: 5, divCAGR: 0.22, divSince: null,
    defaultLens: 'growth',
    inp: { requiredYield: 0.07, divGrowth: 0.10, growth: 0.18, growthCap: 0.16,
           discountRate: 0.095, terminalGrowth: 0.030, bondYield: 4.8 },
  },
  {
    ticker: 'GOOGL', name: 'Alphabet', exchange: 'NASDAQ', currency: 'USD', sector: 'Internet',
    price: 188.00, dayChange: 0.008, eps: 8.10, peTTM: 23.2, forwardPE: 19.8, peg: 1.2,
    dividendRate: 0.84, dividendYield: 0.0045, payoutRatio: 0.10,
    low52: 148.00, high52: 205.00, marketCap: 2.30e12, beta: 1.03, fcf: 70e9, shares: 12.2e9,
    normalPE: 22, priceCAGR: 0.17, epsCAGR: 0.16, seed: 9, divCAGR: 0.20, divSince: 2024,
    defaultLens: 'growth',
    inp: { requiredYield: 0.08, divGrowth: 0.10, growth: 0.14, growthCap: 0.14,
           discountRate: 0.090, terminalGrowth: 0.030, bondYield: 4.8 },
  },
  {
    ticker: 'AMZN', name: 'Amazon.com', exchange: 'NASDAQ', currency: 'USD', sector: 'E-commerce / Cloud',
    price: 212.00, dayChange: -0.006, eps: 5.60, peTTM: 37.9, forwardPE: 30.0, peg: 1.3,
    dividendRate: 0, dividendYield: 0, payoutRatio: 0,
    low52: 160.00, high52: 232.00, marketCap: 2.20e12, beta: 1.15, fcf: 48e9, shares: 10.5e9,
    normalPE: 42, priceCAGR: 0.16, epsCAGR: 0.22, seed: 13, divCAGR: 0, divSince: null,
    defaultLens: 'growth',
    inp: { requiredYield: 0.09, divGrowth: 0, growth: 0.20, growthCap: 0.16,
           discountRate: 0.095, terminalGrowth: 0.030, bondYield: 4.8 },
  },
  {
    ticker: 'NXPI', name: 'NXP Semiconductors', exchange: 'NASDAQ', currency: 'USD', sector: 'Halfgeleiders',
    price: 232.00, dayChange: 0.003, eps: 11.20, peTTM: 20.7, forwardPE: 16.5, peg: 1.1,
    dividendRate: 4.30, dividendYield: 0.0185, payoutRatio: 0.38,
    low52: 185.00, high52: 268.00, marketCap: 59e9, beta: 1.40, fcf: 2.1e9, shares: 255e6,
    normalPE: 20, priceCAGR: 0.14, epsCAGR: 0.15, seed: 17, divCAGR: 0.18, divSince: 2018,
    defaultLens: 'growth',
    inp: { requiredYield: 0.08, divGrowth: 0.08, growth: 0.12, growthCap: 0.12,
           discountRate: 0.095, terminalGrowth: 0.030, bondYield: 4.8 },
  },
];

// extra bibliotheek: bekende namen die via de cijfer-API beschikbaar zouden zijn.
// Snel toe te voegen aan de volglijst zonder AI-schatting.
const LIBRARY = [
  { ticker: 'AAPL', name: 'Apple', exchange: 'NASDAQ', currency: 'USD', sector: 'Technologie',
    price: 235.00, dayChange: 0.004, eps: 6.60, peTTM: 35.6, forwardPE: 30.0, peg: 2.4,
    dividendRate: 1.04, dividendYield: 0.0044, payoutRatio: 0.15, low52: 190.00, high52: 260.00,
    marketCap: 3.5e12, beta: 1.10, fcf: 100e9, shares: 14.9e9,
    normalPE: 28, priceCAGR: 0.20, epsCAGR: 0.15, seed: 23, divCAGR: 0.06, divSince: null,
    defaultLens: 'growth',
    inp: { requiredYield: 0.08, divGrowth: 0.06, growth: 0.09, growthCap: 0.12, discountRate: 0.090, terminalGrowth: 0.030, bondYield: 4.8 } },
  { ticker: 'MSFT', name: 'Microsoft', exchange: 'NASDAQ', currency: 'USD', sector: 'Software',
    price: 470.00, dayChange: 0.006, eps: 12.40, peTTM: 37.9, forwardPE: 32.0, peg: 2.2,
    dividendRate: 3.32, dividendYield: 0.0071, payoutRatio: 0.27, low52: 385.00, high52: 500.00,
    marketCap: 3.5e12, beta: 0.90, fcf: 70e9, shares: 7.43e9,
    normalPE: 30, priceCAGR: 0.22, epsCAGR: 0.18, seed: 29, divCAGR: 0.10, divSince: null,
    defaultLens: 'growth',
    inp: { requiredYield: 0.08, divGrowth: 0.10, growth: 0.13, growthCap: 0.14, discountRate: 0.090, terminalGrowth: 0.030, bondYield: 4.8 } },
  { ticker: 'KO', name: 'Coca-Cola', exchange: 'NYSE', currency: 'USD', sector: 'Frisdranken',
    price: 70.00, dayChange: -0.002, eps: 2.90, peTTM: 24.1, forwardPE: 22.0, peg: 3.0,
    dividendRate: 2.04, dividendYield: 0.0291, payoutRatio: 0.70, low52: 60.00, high52: 74.00,
    marketCap: 301e9, beta: 0.55, fcf: 9.5e9, shares: 4.30e9,
    normalPE: 23, priceCAGR: 0.06, epsCAGR: 0.06, seed: 31, divCAGR: 0.045, divSince: null,
    defaultLens: 'dividend',
    inp: { requiredYield: 0.05, divGrowth: 0.035, growth: 0.05, growthCap: 0.08, discountRate: 0.080, terminalGrowth: 0.025, bondYield: 4.8 } },
  { ticker: 'JNJ', name: 'Johnson & Johnson', exchange: 'NYSE', currency: 'USD', sector: 'Gezondheidszorg',
    price: 165.00, dayChange: 0.003, eps: 9.80, peTTM: 16.8, forwardPE: 15.0, peg: 2.0,
    dividendRate: 4.96, dividendYield: 0.0301, payoutRatio: 0.50, low52: 140.00, high52: 175.00,
    marketCap: 397e9, beta: 0.50, fcf: 18e9, shares: 2.40e9,
    normalPE: 16, priceCAGR: 0.05, epsCAGR: 0.05, seed: 37, divCAGR: 0.055, divSince: null,
    defaultLens: 'dividend',
    inp: { requiredYield: 0.055, divGrowth: 0.045, growth: 0.04, growthCap: 0.07, discountRate: 0.080, terminalGrowth: 0.025, bondYield: 4.8 } },
  { ticker: 'PG', name: 'Procter & Gamble', exchange: 'NYSE', currency: 'USD', sector: 'Consumptiegoederen',
    price: 168.00, dayChange: 0.001, eps: 6.80, peTTM: 24.7, forwardPE: 22.0, peg: 4.0,
    dividendRate: 4.03, dividendYield: 0.0240, payoutRatio: 0.60, low52: 150.00, high52: 180.00,
    marketCap: 395e9, beta: 0.40, fcf: 15e9, shares: 2.35e9,
    normalPE: 23, priceCAGR: 0.06, epsCAGR: 0.06, seed: 41, divCAGR: 0.05, divSince: null,
    defaultLens: 'dividend',
    inp: { requiredYield: 0.05, divGrowth: 0.04, growth: 0.05, growthCap: 0.07, discountRate: 0.080, terminalGrowth: 0.025, bondYield: 4.8 } },
  { ticker: 'HEIA', name: 'Heineken', exchange: 'AMS', currency: 'EUR', sector: 'Brouwerij',
    price: 72.00, dayChange: -0.005, eps: 4.20, peTTM: 17.1, forwardPE: 14.0, peg: 1.7,
    dividendRate: 1.73, dividendYield: 0.0240, payoutRatio: 0.41, low52: 65.00, high52: 95.00,
    marketCap: 41e9, beta: 0.70, fcf: 2.0e9, shares: 568e6,
    normalPE: 18, priceCAGR: 0.04, epsCAGR: 0.05, seed: 43, divCAGR: 0.04, divSince: null,
    defaultLens: 'dividend',
    inp: { requiredYield: 0.055, divGrowth: 0.035, growth: 0.06, growthCap: 0.09, discountRate: 0.085, terminalGrowth: 0.025, bondYield: 4.8 } },
  { ticker: 'INGA', name: 'ING Groep', exchange: 'AMS', currency: 'EUR', sector: 'Bank',
    price: 18.50, dayChange: 0.008, eps: 2.60, peTTM: 7.1, forwardPE: 7.0, peg: 1.2,
    dividendRate: 1.10, dividendYield: 0.0595, payoutRatio: 0.50, low52: 14.00, high52: 20.00,
    marketCap: 60e9, beta: 1.20, fcf: 6.0e9, shares: 3.24e9,
    normalPE: 8, priceCAGR: 0.07, epsCAGR: 0.05, seed: 47, divCAGR: 0.08, divSince: null,
    defaultLens: 'dividend',
    inp: { requiredYield: 0.075, divGrowth: 0.03, growth: 0.04, growthCap: 0.08, discountRate: 0.090, terminalGrowth: 0.025, bondYield: 4.8 } },
  { ticker: 'SHEL', name: 'Shell', exchange: 'AMS', currency: 'EUR', sector: 'Energie',
    price: 33.00, dayChange: 0.002, eps: 4.00, peTTM: 8.3, forwardPE: 8.0, peg: 1.5,
    dividendRate: 1.30, dividendYield: 0.0394, payoutRatio: 0.33, low52: 28.00, high52: 37.00,
    marketCap: 200e9, beta: 0.90, fcf: 30e9, shares: 6.10e9,
    normalPE: 9, priceCAGR: 0.05, epsCAGR: 0.04, seed: 53, divCAGR: 0.04, divSince: null,
    defaultLens: 'dividend',
    inp: { requiredYield: 0.07, divGrowth: 0.03, growth: 0.03, growthCap: 0.07, discountRate: 0.090, terminalGrowth: 0.025, bondYield: 4.8 } },
];

// Bouw een weergavebaar aandeel uit een seed + (live) marktdata. GEEN synthese:
// history/divHistory komen uitsluitend uit echte Yahoo-series (s.priceHistory /
// s.divHistory). Ontbreken die, dan blijven de arrays leeg → de UI toont een
// lege staat ("Niet beschikbaar") i.p.v. verzonnen data.
function hydrate(s) {
  const eps = numD(s.eps);
  const shares = numD(s.shares);
  const fcf = numD(s.fcf);
  const fcfPerShare = (fcf != null && shares) ? fcf / shares : null;

  // "Normale K/W" (blauw) = historische mediaan-P/E; reële-waardeband op echte WPA
  const { history, normalPE, hasEps } = buildFairHistory(s.priceHistory, s.epsHistory, s.normalPE);
  const price = numD(s.price);
  const cy = new Date().getFullYear();
  if (hasEps && eps != null && price != null && (!history.length || history[history.length - 1].year < cy)) {
    history.push({ year: cy, price, eps, fair: normalPE != null ? +(eps * normalPE).toFixed(2) : null });
  }
  const divHistory = Array.isArray(s.divHistory) ? s.divHistory : [];

  // "Fair value" (oranje) = analisten-P/E = mean target ÷ forward-WPA (sector via AI).
  const tgt = numD(s.targetMeanPrice), fe = numD(s.forwardEps), fpe = numD(s.forwardPE);
  let fairPE = null;
  if (tgt != null && fe > 0) fairPE = +(tgt / fe).toFixed(1);
  else if (fpe != null && fpe > 0) fairPE = +fpe.toFixed(1);
  else fairPE = normalPE;
  // groei-default: analistenconsensus (+1j) gekrompen naar een langjarig niveau
  const growthDefault = seedGrowth(s.inp, s.analystGrowth);

  return {
    ...s,
    normalPE,
    fcfPerShare,
    cashflowPerShare: fcfPerShare,
    history,
    divHistory,
    nextDividend: s.nextDividend ?? null,
    // default-inputs voor de twee lenzen, aangevuld met afgeleiden
    inputs: {
      dividend: s.dividendRate,
      requiredYield: s.inp.requiredYield,
      divGrowth: s.inp.divGrowth,
      eps,
      cashflowPerShare: fcfPerShare,
      growth: growthDefault,
      growthCap: s.inp.growthCap,
      discountRate: s.inp.discountRate,
      terminalGrowth: s.inp.terminalGrowth,
      bondYield: s.inp.bondYield,
      fairPE: numD(s.inp && s.inp.fairPE) ?? fairPE,
      safetyMargin: 0.15,
    },
  };
}

// ── DATALAAG ────────────────────────────────────────────────────────────────
// Alle marktcijfers komen LIVE van /api/fundamentals (Yahoo + FMP). De seeds
// leveren alleen bootstrap (ticker/naam/beurs/valuta/lens + aanname-`inp`); hun
// numerieke velden worden altijd overschreven door live data of op null gezet —
// nooit als mock getoond.

// Marktvelden gevuld uit de live respons (afgeleiden meeberekend).
function mergeLive(seed, d) {
  const price = numD(d.price);
  const eps = numD(d.eps);
  const shares = numD(d.shares);
  const dividendRate = numD(d.dividendRate);
  // PEG met dezelfde groei als de waardering (zie seedGrowth in hydrate)
  const g = seedGrowth(seed.inp, d.analystGrowth);
  return {
    ...seed,
    name: seed.name || d.name || seed.ticker,
    exchange: seed.exchange || d.exchange || '—',
    currency: d.currency || seed.currency,
    sector: d.sector || seed.sector || '—',
    price,
    dayChange: numD(d.dayChange) ?? 0,
    eps,
    peTTM: (price != null && eps > 0) ? price / eps : null,
    forwardPE: numD(d.forwardPE),
    peg: (eps > 0 && g > 0) ? (price / eps) / (g * 100) : null,
    dividendRate,
    dividendYield: dividendRate == null ? null : (price ? dividendRate / price : 0),
    payoutRatio: numD(d.payoutRatio),
    low52: numD(d.low52),
    high52: numD(d.high52),
    marketCap: numD(d.marketCap) ?? ((price != null && shares != null) ? price * shares : null),
    beta: numD(d.beta),
    fcf: numD(d.fcf),
    shares,
    forwardEps: numD(d.forwardEps),
    targetMeanPrice: numD(d.targetMeanPrice),
    analystGrowth: numD(d.analystGrowth),
    recommendationKey: d.recommendationKey || null,
    // balans & kwaliteit
    totalDebt: numD(d.totalDebt),
    totalCash: numD(d.totalCash),
    debtToEquity: numD(d.debtToEquity),
    returnOnEquity: numD(d.returnOnEquity),
    profitMargins: numD(d.profitMargins),
    revenueGrowth: numD(d.revenueGrowth),
    website: d.website || null,
    // vintage: wanneer dit snapshot is opgehaald + per welke rapportagedatum
    fiscalAsOf: d.fiscalAsOf || null,
    loadedAt: Date.now(),
    priceHistory: Array.isArray(d.priceHistory) ? d.priceHistory : [],
    priceMonthly: Array.isArray(d.priceMonthly) ? d.priceMonthly : [],
    divHistory: Array.isArray(d.divHistory) ? d.divHistory : [],
    epsHistory: Array.isArray(d.epsHistory) ? d.epsHistory : [],
    financials: d.financials || null,
  };
}

// Alle marktvelden op null — gebruikt wanneer er geen live data is (geen mock).
function blankMarket(seed) {
  return {
    ...seed,
    price: null, dayChange: null, eps: null, peTTM: null, forwardPE: null, peg: null,
    dividendRate: null, dividendYield: null, payoutRatio: null,
    low52: null, high52: null, marketCap: null, beta: null, fcf: null, shares: null,
    forwardEps: null, targetMeanPrice: null, analystGrowth: null, recommendationKey: null,
    totalDebt: null, totalCash: null, debtToEquity: null, returnOnEquity: null,
    profitMargins: null, revenueGrowth: null, website: null, fiscalAsOf: null, loadedAt: null,
    sector: seed.sector || '—', priceHistory: [], priceMonthly: [], divHistory: [], epsHistory: [],
    financials: null,
  };
}

// Haal live cijfers op voor één seed en geef een gehydrateerd aandeel terug.
async function withLiveData(seed) {
  try {
    const symQ = seed.ySymbol ? `&symbol=${encodeURIComponent(seed.ySymbol)}` : '';
    const res = await fetch(`/api/fundamentals?ticker=${encodeURIComponent(seed.ticker)}&exchange=${encodeURIComponent(seed.exchange || '')}${symQ}`);
    if (!res.ok) return hydrate(blankMarket(seed));
    const d = await res.json();
    if (d.error || d.price == null) return hydrate(blankMarket(seed));
    return hydrate(mergeLive(seed, d));
  } catch {
    return hydrate(blankMarket(seed));
  }
}

async function fetchQuotes() {
  return Promise.all(RAW.map((seed) => withLiveData(seed)));
}

// Zoek een bootstrap-seed (basis + bibliotheek) en haal er live data bij.
const ALL_SEEDS = [...RAW, ...LIBRARY];
async function liveLookup(ticker) {
  const s = ALL_SEEDS.find((x) => x.ticker === String(ticker).toUpperCase());
  return s ? withLiveData(s) : null;
}
function hydrateStock(seed) { return hydrate(seed); }
const LIBRARY_SUGGESTIONS = LIBRARY.map((s) => ({ ticker: s.ticker, name: s.name }));
const BASE_TICKERS = RAW.map((s) => s.ticker);

Object.assign(window, { fetchQuotes, liveLookup, withLiveData, hydrateStock, buildFairHistory, defaultGrowth, LIBRARY_SUGGESTIONS, BASE_TICKERS });
