/**
 * WS4: Competitor Change Detection
 *
 * Compares current scrape results with previous observations
 * and generates alerts for price changes, new products, stock changes.
 */
import { Pool } from "pg";

const pool = new Pool({
  host: process.env.POSTGRES_HOST || "localhost",
  port: parseInt(process.env.POSTGRES_PORT || "5433"),
  database: process.env.POSTGRES_DB || "transceiver_db",
  user: process.env.POSTGRES_USER || "tip",
  password: process.env.POSTGRES_PASSWORD || "tip_dev_2026",
  max: 3,
});

interface PriceObservation {
  transceiver_id: string;
  vendor_id: string;
  price: number;
  currency: string;
  stock_level?: string;
  part_number?: string;
  product_name?: string;
  form_factor?: string;
  speed_gbps?: number;
  source_url?: string;
}

/**
 * After a scraper run, call this to detect changes and generate alerts.
 */
export async function detectChanges(
  vendorId: string,
  currentObservations: PriceObservation[]
): Promise<{ alerts: number; priceChanges: number; newProducts: number }> {
  let alerts = 0;
  let priceChanges = 0;
  let newProducts = 0;

  for (const obs of currentObservations) {
    try {
      // Get last known price for this transceiver from this vendor
      const prev = await pool.query(
        `SELECT price, currency, stock_level
         FROM price_observations
         WHERE transceiver_id = $1 AND source_vendor_id = $2
         ORDER BY time DESC LIMIT 1`,
        [obs.transceiver_id, obs.vendor_id]
      );

      if (prev.rows.length === 0) {
        // New product alert
        await pool.query(
          `INSERT INTO competitor_alerts (vendor_id, transceiver_id, alert_type, severity,
            new_price, currency, part_number, product_name, form_factor, speed_gbps, source_url)
           VALUES ($1, $2, 'new_product', 'medium', $3, $4, $5, $6, $7, $8, $9)`,
          [obs.vendor_id, obs.transceiver_id, obs.price, obs.currency,
           obs.part_number, obs.product_name, obs.form_factor, obs.speed_gbps, obs.source_url]
        );
        newProducts++;
        alerts++;
        continue;
      }

      const prevPrice = parseFloat(prev.rows[0].price);
      const prevStock = prev.rows[0].stock_level;

      // Price change detection (>2% threshold to avoid noise)
      if (Math.abs(obs.price - prevPrice) / prevPrice > 0.02) {
        const delta = obs.price - prevPrice;
        const deltaPct = (delta / prevPrice) * 100;
        const alertType = delta < 0 ? 'price_drop' : 'price_increase';
        const severity = Math.abs(deltaPct) > 15 ? 'high' : Math.abs(deltaPct) > 5 ? 'medium' : 'low';

        // Insert alert
        await pool.query(
          `INSERT INTO competitor_alerts (vendor_id, transceiver_id, alert_type, severity,
            old_price, new_price, price_delta, price_pct, currency,
            part_number, product_name, form_factor, speed_gbps, source_url)
           VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)`,
          [obs.vendor_id, obs.transceiver_id, alertType, severity,
           prevPrice, obs.price, delta, deltaPct, obs.currency,
           obs.part_number, obs.product_name, obs.form_factor, obs.speed_gbps, obs.source_url]
        );

        // Insert price change record
        await pool.query(
          `INSERT INTO price_changes (transceiver_id, vendor_id, old_price, new_price, delta, delta_pct, currency)
           VALUES ($1, $2, $3, $4, $5, $6, $7)`,
          [obs.transceiver_id, obs.vendor_id, prevPrice, obs.price, delta, deltaPct, obs.currency]
        );

        priceChanges++;
        alerts++;
      }

      // Stock change detection
      if (prevStock && obs.stock_level && prevStock !== obs.stock_level) {
        if (obs.stock_level === 'out_of_stock' && prevStock !== 'out_of_stock') {
          await pool.query(
            `INSERT INTO competitor_alerts (vendor_id, transceiver_id, alert_type, severity,
              part_number, product_name, form_factor, speed_gbps, source_url)
             VALUES ($1, $2, 'out_of_stock', 'low', $3, $4, $5, $6, $7)`,
            [obs.vendor_id, obs.transceiver_id, obs.part_number, obs.product_name,
             obs.form_factor, obs.speed_gbps, obs.source_url]
          );
          alerts++;
        } else if (prevStock === 'out_of_stock' && obs.stock_level !== 'out_of_stock') {
          await pool.query(
            `INSERT INTO competitor_alerts (vendor_id, transceiver_id, alert_type, severity,
              new_price, currency, part_number, product_name, form_factor, speed_gbps, source_url)
             VALUES ($1, $2, 'back_in_stock', 'low', $3, $4, $5, $6, $7, $8, $9)`,
            [obs.vendor_id, obs.transceiver_id, obs.price, obs.currency,
             obs.part_number, obs.product_name, obs.form_factor, obs.speed_gbps, obs.source_url]
          );
          alerts++;
        }
      }
    } catch (err) {
      console.error(`Change detection error for ${obs.part_number}:`, err);
    }
  }

  console.log(`Change detection: ${alerts} alerts (${priceChanges} price changes, ${newProducts} new products)`);
  return { alerts, priceChanges, newProducts };
}
