// utils/portfolioSim.js
function mulberry32(seed) {
  let a = seed >>> 0;
  return function () {
    a |= 0;
    a = (a + 0x6D2B79F5) | 0;
    let t = Math.imul(a ^ (a >>> 15), 1 | a);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

function hashToSeed(str) {
  let h = 2166136261;
  for (let i = 0; i < str.length; i++) {
    h ^= str.charCodeAt(i);
    h = Math.imul(h, 16777619);
  }
  return h >>> 0;
}

/**
 * Random-walk series ending at currentPrice.
 * Deterministic per (userId + symbol + period).
 */
function generatePriceSeries({
  userId,
  symbol,
  currentPrice,
  points,
  drift = 0.0006,     // upward bias
  vol = 0.02,         // volatility factor
  floorPct = 0.35,    // min bound relative to current
}) {
  const seed = hashToSeed(`${userId}:${symbol}:${points}`);
  const rand = mulberry32(seed);

  const cur = Number(currentPrice || 0) || 0;
  if (cur <= 0 || points <= 1) {
    return Array.from({ length: Math.max(points, 2) }, (_, i) => ({
      t: i,
      price: cur,
    }));
  }

  const minPrice = cur * floorPct;

  // start lower than current, then walk to current
  let price = cur * (0.65 + rand() * 0.25);

  const series = [];
  for (let i = 0; i < points; i++) {
    const shock = (rand() - 0.5) * 2;        // [-1,1]
    const step = drift + shock * vol * 0.25; // small step
    price = price * (1 + step);

    if (price < minPrice) price = minPrice * (0.98 + rand() * 0.04);

    series.push({ t: i, price: Number(price.toFixed(8)) });
  }

  // force last point to current
  series[series.length - 1].price = Number(cur.toFixed(8));
  return series;
}

/**
 * Portfolio series: sum(value_i(t)) using fixed holdings quantity and series prices
 */
function generatePortfolioSeries({ items, seriesBySymbol, points }) {
  const out = [];
  for (let i = 0; i < points; i++) {
    let total = 0;
    for (const it of items) {
      const sym = it.symbol;
      const qty = Number(it.holdings || 0) || 0;
      const p = (seriesBySymbol[sym]?.[i]?.price ?? Number(it.price || 0)) || 0;
      total += qty * p;
    }
    out.push({ time: i, value: Number(total.toFixed(2)) });
  }
  return out;
}

function generateMonthlyPnl({ userId, portfolioSeries }) {
  // last 7 buckets (months-like). Use deltas from the portfolio series.
  const seed = hashToSeed(`${userId}:monthlypnl`);
  const rand = mulberry32(seed);

  const labels = ["Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"];
  const last = portfolioSeries?.[portfolioSeries.length - 1]?.value ?? 0;

  // create 7 pnl points around recent value
  let base = last * 0.05; // 5% scale
  return labels.map((m, idx) => {
    const sign = rand() > 0.35 ? 1 : -1;
    const mag = base * (0.35 + rand());
    const pnl = sign * mag * (0.6 + idx / 12);
    const percent = last > 0 ? (pnl / last) * 100 : 0;
    return {
      month: m,
      pnl: Number(pnl.toFixed(2)),
      percent: Number(percent.toFixed(2)),
    };
  });
}

module.exports = {
  generatePriceSeries,
  generatePortfolioSeries,
  generateMonthlyPnl,
};