/**
 * Price Forecast — Linear Regression
 *
 * Routes:
 *   GET /api/price-forecast/:id   — 30-day forecast for a transceiver
 */
import { Router, Request, Response } from "express";
import { pool } from "../db/client";

export const priceForecastRouter = Router();

const MIN_PRICE = 0.01;

function linearRegression(xs: number[], ys: number[]): { slope: number; intercept: number; rSquared: number } {
  const n = xs.length;
  if (n < 2) return { slope: 0, intercept: ys[0] ?? 0, rSquared: 0 };

  const sumX  = xs.reduce((a, b) => a + b, 0);
  const sumY  = ys.reduce((a, b) => a + b, 0);
  const sumXY = xs.reduce((acc, x, i) => acc + x * ys[i], 0);
  const sumX2 = xs.reduce((acc, x) => acc + x * x, 0);

  const slope     = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
  const intercept = (sumY - slope * sumX) / n;

  const yMean  = sumY / n;
  const ssTot  = ys.reduce((acc, y) => acc + (y - yMean) ** 2, 0);
  const ssRes  = xs.reduce((acc, x, i) => acc + (ys[i] - (slope * x + intercept)) ** 2, 0);
  const rSquared = ssTot === 0 ? 0 : 1 - ssRes / ssTot;

  return { slope, intercept, rSquared };
}

function addDays(base: Date, n: number): string {
  const d = new Date(base);
  d.setUTCDate(d.getUTCDate() + n);
  return d.toISOString().slice(0, 10);
}

// ─── GET /api/price-forecast/:id ─────────────────────────────────────────────
priceForecastRouter.get("/:id", async (req: Request, res: Response) => {
  try {
    const id = parseInt(String(req.params.id), 10);
    if (!Number.isFinite(id) || id <= 0) {
      res.status(400).json({ success: false, error: "Invalid transceiver id" });
      return;
    }

    const histResult = await pool.query<{ day: Date; avg_price: string }>(
      `SELECT
         DATE(time)             AS day,
         AVG(price)             AS avg_price
       FROM price_observations
       WHERE transceiver_id = $1
         AND time > NOW() - INTERVAL '90 days'
       GROUP BY DATE(time)
       ORDER BY day`,
      [id]
    );

    if (histResult.rows.length === 0) {
      res.status(404).json({ success: false, error: "No price history found for this transceiver" });
      return;
    }

    const history = histResult.rows.map((r) => ({
      date:      r.day.toISOString().slice(0, 10),
      avg_price: parseFloat(r.avg_price),
    }));

    // Use day-0 offset as x axis so numbers stay small
    const epoch0 = new Date(history[0].date + "T00:00:00Z").getTime();
    const xs = history.map((h) => (new Date(h.date + "T00:00:00Z").getTime() - epoch0) / 86_400_000);
    const ys = history.map((h) => h.avg_price);

    const { slope, intercept, rSquared } = linearRegression(xs, ys);

    const lastDate  = new Date(history[history.length - 1].date + "T00:00:00Z");
    const lastX     = xs[xs.length - 1];
    const forecast  = Array.from({ length: 30 }, (_, i) => {
      const dayOffset    = lastX + i + 1;
      const rawPrice     = slope * dayOffset + intercept;
      const predictedPrice = Math.max(MIN_PRICE, Math.round(rawPrice * 100) / 100);
      return {
        date:            addDays(lastDate, i + 1),
        predicted_price: predictedPrice,
        is_forecast:     true,
      };
    });

    const trend =
      slope >  0.05 ? "rising"   :
      slope < -0.05 ? "declining" : "stable";

    const forecast30dPrice = forecast[29].predicted_price;

    res.json({
      success:          true,
      transceiver_id:   id,
      history,
      forecast,
      trend,
      slope_per_day:    Math.round(slope * 10_000) / 10_000,
      r_squared:        Math.round(rSquared * 100) / 100,
      forecast_30d_price: forecast30dPrice,
    });
  } catch (err) {
    console.error("GET /api/price-forecast/:id error:", err);
    res.status(500).json({ success: false, error: String(err) });
  }
});
