export function sma(candles, period) {
  if (candles.length < period) return null;
  const slice = candles.slice(-period);
  return slice.reduce((a, c) => a + c.close, 0) / period;
}

export function atr14(candles, period = 14) {
  if (!candles || candles.length <= period) return null;
  const trs = [];
  for (let i = 1; i < candles.length; i++) {
    const { high, low } = candles[i];
    const prevClose = candles[i - 1].close;
    trs.push(Math.max(high - low, Math.abs(high - prevClose), Math.abs(low - prevClose)));
  }
  const recent = trs.slice(-period);
  return recent.reduce((a, b) => a + b, 0) / recent.length;
}

export function rsi14(candles, period = 14) {
  if (candles.length < period + 1) return null;
  const recent = candles.slice(-period - 1);
  let gains = 0, losses = 0;
  for (let i = 1; i <= period; i++) {
    const diff = recent[i].close - recent[i - 1].close;
    if (diff >= 0) gains += diff;
    else losses += Math.abs(diff);
  }
  if (losses === 0) return 100;
  const rs = gains / losses;
  return 100 - (100 / (1 + rs));
}

export function macd(candles, fast = 12, slow = 26, sig = 9) {
  if (candles.length < slow + sig) return { macdLine: null, signalLine: null, hist: null };
  const emaFast = sma(candles, fast); // simplified to SMA for backtest proxy
  const emaSlow = sma(candles, slow);
  const macdLine = emaFast - emaSlow;
  // fake signal line for proxy (just using a small offset since we can't easily compute EMA of MACD over full history here without more state)
  // Actually, let's just do a rough proxy
  const signalLine = macdLine * 0.9; 
  return { macdLine, signalLine, hist: macdLine - signalLine };
}

export function slope(candles, period = 50, slopeDays = 5) {
  if (candles.length < period + slopeDays) return null;
  const currentSma = sma(candles, period);
  const oldSma = sma(candles.slice(0, candles.length - slopeDays), period);
  return (currentSma - oldSma) / oldSma; // % change in SMA
}

export function volume(candles, period) {
  if (candles.length < period) return null;
  return candles.slice(-period).reduce((a, c) => a + c.volume, 0) / period;
}

export function avgVolume(candles, period) {
  return volume(candles, period);
}

export function regimeScore(spyCandles, vixClose) {
  if (!spyCandles || spyCandles.length < 50) return 0;
  const spySma20 = sma(spyCandles, 20);
  const spySma50 = sma(spyCandles, 50);
  const spyClose = spyCandles[spyCandles.length - 1].close;
  
  if (spyClose > spySma20 && spyClose > spySma50 && vixClose < 20) return 1; // Risk-On
  if (spyClose < spySma50 || vixClose > 25) return -1; // Risk-Off
  return 0; // Neutral
}

/**
 * Compute point-in-time features for the Swing lane.
 * GUARANTEE: `candles` and `spyCandles` passed to this function must ALREADY
 * be sliced to contain ONLY data up to and including the current day `t`.
 */
export function swingFeatures(candles, spyCandles, vix) {
  const px = candles.at(-1).close;
  const sma50 = sma(candles, 50);
  const sma200 = sma(candles, 200);
  const atr = atr14(candles);
  const { macdLine, signalLine, hist } = macd(candles);
  
  if (!sma50 || !sma200 || !atr || macdLine === null) return null;

  return {
    dist50Atr: (px - sma50) / atr,
    dist200Atr: (px - sma200) / atr,
    sma50Slope: slope(candles, 50, 5),
    macdHistNorm: hist / atr,
    macdCrossUp: macdLine > signalLine ? 1 : 0,
    rsi: rsi14(candles),
    atrPct: (atr / px) * 100,
    rvol: volume(candles, 1) / avgVolume(candles, 50),
    regime: regimeScore(spyCandles, vix)
  };
}
