/**
 * Volume Forecasting — Exponential Smoothing with Confidence Bands
 * Pure JS, no external dependencies
 */

/**
 * Simple Exponential Smoothing (SES) forecast
 * @param {number[]} data - Historical time series values
 * @param {number} periodsAhead - Number of periods to forecast
 * @param {number} alpha - Smoothing factor (0-1), default 0.3
 * @returns {{ forecast: number[], confidence: { upper: number[], lower: number[] }, fitted: number[] }}
 */
function forecast(data, periodsAhead = 7, alpha = 0.3) {
  if (!data || data.length === 0) {
    return { forecast: [], confidence: { upper: [], lower: [] }, fitted: [] };
  }

  // Initialize with first value
  const n = data.length;
  const fitted = new Array(n);
  fitted[0] = data[0];

  // Fit the model
  for (let i = 1; i < n; i++) {
    fitted[i] = alpha * data[i] + (1 - alpha) * fitted[i - 1];
  }

  // Calculate residuals for confidence bands
  const residuals = data.map((v, i) => v - fitted[i]);
  const mse = residuals.reduce((s, r) => s + r * r, 0) / n;
  const rmse = Math.sqrt(mse);

  // Forecast
  const lastFitted = fitted[n - 1];
  const forecastValues = [];
  const upper = [];
  const lower = [];

  // Also apply Holt's trend if data shows clear trend
  const trendWindow = Math.min(7, Math.floor(n / 2));
  let trend = 0;
  if (n >= 4) {
    const recentAvg = data.slice(-trendWindow).reduce((s, v) => s + v, 0) / trendWindow;
    const olderAvg = data.slice(-trendWindow * 2, -trendWindow).reduce((s, v) => s + v, 0) / Math.min(trendWindow, data.slice(-trendWindow * 2, -trendWindow).length || 1);
    if (olderAvg > 0) {
      trend = (recentAvg - olderAvg) / trendWindow;
    }
  }

  for (let i = 1; i <= periodsAhead; i++) {
    const predicted = lastFitted + trend * i;
    const confidenceWidth = rmse * 1.96 * Math.sqrt(i); // 95% confidence
    forecastValues.push(Math.max(0, Math.round(predicted * 100) / 100));
    upper.push(Math.max(0, Math.round((predicted + confidenceWidth) * 100) / 100));
    lower.push(Math.max(0, Math.round((predicted - confidenceWidth) * 100) / 100));
  }

  return {
    forecast: forecastValues,
    confidence: { upper, lower },
    fitted: fitted.map(v => Math.round(v * 100) / 100)
  };
}

/**
 * Prepare time series from daily trend data and forecast ahead
 * @param {Object[]} trendData - Array of { dia, vol_usd } or { dia, qtd }
 * @param {string} metric - 'vol_usd' or 'qtd'
 * @param {number} daysAhead - Days to forecast
 * @returns {{ historical: Object[], predicted: Object[], confidence_upper: Object[], confidence_lower: Object[] }}
 */
function forecastFromTrend(trendData, metric = 'vol_usd', daysAhead = 30) {
  if (!trendData || trendData.length < 3) {
    return { historical: trendData || [], predicted: [], confidence_upper: [], confidence_lower: [] };
  }

  const values = trendData.map(d => Number(d[metric]) || 0);
  const result = forecast(values, daysAhead);

  // Generate future dates
  const lastDate = new Date(trendData[trendData.length - 1].dia);
  const predicted = [];
  const confUpper = [];
  const confLower = [];

  for (let i = 0; i < daysAhead; i++) {
    const d = new Date(lastDate);
    d.setDate(d.getDate() + i + 1);
    const dia = d.toISOString().slice(0, 10);
    predicted.push({ dia, [metric]: result.forecast[i] });
    confUpper.push({ dia, [metric]: result.confidence.upper[i] });
    confLower.push({ dia, [metric]: result.confidence.lower[i] });
  }

  return {
    historical: trendData,
    predicted,
    confidence_upper: confUpper,
    confidence_lower: confLower
  };
}

module.exports = { forecast, forecastFromTrend };
