import { Router, Request, Response, NextFunction } from "express";
import { pool } from "../db/client";
import { listVendors } from "../db/queries";

export const vendorRouter = Router();

// GET /api/vendors — List all vendors
vendorRouter.get("/", async (req: Request, res: Response) => {
  try {
    const vendors = await listVendors(req.query.type ? String(req.query.type) : undefined);
    res.json({ success: true, data: vendors, total: vendors.length });
  } catch (err) {
    console.error("List vendors error:", err);
    res.status(500).json({ success: false, error: "Internal server error" });
  }
});

// POST /api/vendors — Create a new vendor + queue auto-crawl
vendorRouter.post("/", async (req: Request, res: Response) => {
  try {
    const {
      name,
      type,
      website,
      shop_url,
      headquarters,
      country,
      founded_year,
      revenue_usd,
      employee_count,
      market_position,
      specialties,
      is_competitor,
    } = req.body as Record<string, any>;

    if (!name || typeof name !== "string" || !name.trim()) {
      return res.status(400).json({ success: false, error: "name is required" });
    }

    const validTypes = ["manufacturer", "distributor", "oem", "reseller", "compatible"];
    const resolvedType = validTypes.includes(type) ? type : "compatible";

    // Generate slug from name
    const slug = name
      .trim()
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, "-")
      .replace(/^-|-$/g, "");

    // Build specialties array
    const specialtiesArr: string[] = Array.isArray(specialties)
      ? specialties
      : typeof specialties === "string" && specialties.trim()
      ? specialties.split(",").map((s: string) => s.trim()).filter(Boolean)
      : [];

    // Insert vendor
    const insertResult = await pool.query(
      `INSERT INTO vendors
         (name, slug, type, website, shop_url, headquarters, country,
          founded_year, revenue_usd, employee_count, market_position, specialties,
          is_competitor, scrape_config)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
       RETURNING *`,
      [
        name.trim(),
        slug,
        resolvedType,
        website || null,
        shop_url || website || null,
        headquarters || null,
        country || null,
        founded_year ? Number(founded_year) : null,
        revenue_usd ? Number(revenue_usd) : null,
        employee_count ? Number(employee_count) : null,
        market_position || null,
        specialtiesArr,
        is_competitor === true || is_competitor === "true",
        website ? JSON.stringify({ url: website, enabled: true, auto_queued: true }) : "{}",
      ]
    );

    const vendor = insertResult.rows[0];

    // Queue crawl job: insert into crawler_llm_log as a pending task signal
    // The scraper fleet polls for new vendors with scrape_config.enabled=true
    if (website) {
      await pool
        .query(
          `INSERT INTO crawler_llm_log
             (vendor_id, url, action, model, tokens_used, created_at)
           VALUES ($1, $2, 'vendor_created_auto_crawl', 'system', 0, NOW())`,
          [vendor.id, website]
        )
        .catch(() => null); // Non-fatal — vendor is created regardless
    }

    return res.status(201).json({
      success: true,
      vendor,
      crawl_queued: !!website,
      message: website
        ? `Vendor "${name}" created. Auto-crawl queued for ${website}.`
        : `Vendor "${name}" created. Add a website URL to enable auto-crawl.`,
    });
  } catch (err: any) {
    if (err.code === "23505") {
      // Unique constraint violation (name or slug)
      return res.status(409).json({ success: false, error: "A vendor with this name already exists." });
    }
    console.error("Create vendor error:", err);
    return res.status(500).json({ success: false, error: "Internal server error" });
  }
});

// GET /api/vendors/:id — Get single vendor with full stats
// GET /api/vendors/reliability — per-vendor data-reliability scores (freshness/frequency/coverage)
vendorRouter.get("/reliability", async (_req: Request, res: Response) => {
  try {
    const result = await pool.query(`
      SELECT v.id::text AS vendor_id, v.name AS vendor_name,
             COUNT(DISTINCT t.id)::int     AS sku_count,
             COUNT(po.transceiver_id)::int AS obs_count,
             MAX(po.time)                  AS last_obs
      FROM vendors v
      JOIN transceivers t ON t.vendor_id = v.id
      LEFT JOIN price_observations po ON po.transceiver_id = t.id
      GROUP BY v.id, v.name
      HAVING COUNT(DISTINCT t.id) > 0`);
    const rows = result.rows as Array<{ vendor_id: string; vendor_name: string; sku_count: number; obs_count: number; last_obs: string | null }>;
    const maxSku = Math.max(1, ...rows.map((r) => r.sku_count));
    const maxObs = Math.max(1, ...rows.map((r) => r.obs_count));
    const now = Date.now();
    const vendors = rows.map((r) => {
      const daysStale = r.last_obs ? Math.max(0, (now - new Date(r.last_obs).getTime()) / 86400000) : 999;
      const freshness_score = Math.max(0, Math.min(100, Math.round(100 - daysStale * 3)));
      const frequency_score = Math.round(100 * Math.min(1, Math.log10(r.obs_count + 1) / Math.log10(maxObs + 1)));
      const coverage_score = Math.round(100 * Math.min(1, r.sku_count / maxSku));
      const reliability_score = Math.round(0.4 * freshness_score + 0.3 * frequency_score + 0.3 * coverage_score);
      return { vendor_id: r.vendor_id, vendor_name: r.vendor_name, sku_count: r.sku_count, obs_count: r.obs_count, last_obs: r.last_obs, freshness_score, frequency_score, coverage_score, reliability_score };
    });
    vendors.sort((a, b) => b.reliability_score - a.reliability_score);
    res.json({ success: true, count: vendors.length, vendors });
  } catch (err) {
    console.error("vendor reliability error:", err);
    res.status(500).json({ success: false, error: "Failed to compute vendor reliability" });
  }
});

vendorRouter.get("/:id", async (req: Request, res: Response, next: NextFunction) => {
  if (req.params.id === "market-share" || req.params.id === "intelligence") return next();
  try {
    const { id } = req.params;
    const result = await pool.query(
      `SELECT v.*,
              (SELECT COUNT(*) FROM transceivers t WHERE t.vendor_id = v.id)::int AS transceiver_count,
              (SELECT COUNT(*) FROM switches s WHERE s.vendor_id = v.id)::int AS switch_count,
              (SELECT COUNT(*) FROM price_observations po
               JOIN transceivers t ON po.transceiver_id = t.id
               WHERE t.vendor_id = v.id)::int AS price_obs_count
       FROM vendors v
       WHERE v.id::text = $1 OR v.slug = $1`,
      [id]
    );
    const vendor = result.rows[0];
    if (!vendor) return res.status(404).json({ success: false, error: "Vendor not found" });
    return res.json({ success: true, vendor });
  } catch (err) {
    console.error("Get vendor error:", err);
    return res.status(500).json({ success: false, error: "Internal server error" });
  }
});

// ─────────────────────────────────────────────────────────────────────────────
// GET /api/vendors/market-share — Weekly SKU-coverage share per vendor over time
// Shows which vendors are gaining/losing market presence
// Query params: speed_gbps, form_factor, days (default 90)
// ─────────────────────────────────────────────────────────────────────────────
vendorRouter.get("/market-share", async (req: Request, res: Response) => {
  const days = Math.min(parseInt(req.query.days as string) || 90, 365);
  const spd  = req.query.speed_gbps  as string | undefined;
  const ff   = req.query.form_factor as string | undefined;

  try {
    const [weekly, current, momentum] = await Promise.all([
      // Weekly SKU count per vendor — shows growth/shrink trends
      pool.query(`
        SELECT
          DATE_TRUNC('week', po.time)::date  AS week,
          v.id::text                         AS vendor_id,
          v.name                             AS vendor_name,
          COUNT(DISTINCT po.transceiver_id)::int AS sku_count
        FROM price_observations po
        JOIN vendors v      ON v.id  = po.source_vendor_id
        JOIN transceivers t ON t.id  = po.transceiver_id
        WHERE po.time >= NOW() - INTERVAL '${days} days'
          AND po.price > 0
          AND COALESCE(po.is_anomalous, false) = false
          ${spd ? `AND t.speed_gbps  = ${parseFloat(spd)}` : ""}
          ${ff  ? `AND t.form_factor = '${ff.replace(/'/g,"''")}'` : ""}
        GROUP BY DATE_TRUNC('week', po.time), v.id, v.name
        ORDER BY week ASC, sku_count DESC
      `),

      // Current snapshot: SKU share % per vendor (last 30d)
      pool.query(`
        WITH totals AS (
          SELECT COUNT(DISTINCT transceiver_id)::float AS total
          FROM price_observations
          WHERE time >= NOW() - INTERVAL '30 days'
            AND price > 0 AND COALESCE(is_anomalous, false) = false
        )
        SELECT
          v.id::text AS vendor_id,
          v.name     AS vendor_name,
          v.type,
          COUNT(DISTINCT po.transceiver_id)::int        AS sku_count,
          ROUND((COUNT(DISTINCT po.transceiver_id)::numeric / NULLIF(t.total,0)::numeric) * 100, 1) AS market_share_pct,
          COUNT(*)::int                             AS total_obs,
          MAX(po.time)                                  AS last_seen
        FROM price_observations po
        JOIN vendors v ON v.id = po.source_vendor_id
        JOIN transceivers tx ON tx.id = po.transceiver_id
        CROSS JOIN totals t
        WHERE po.time >= NOW() - INTERVAL '30 days'
          AND po.price > 0
          AND COALESCE(po.is_anomalous, false) = false
          ${spd ? `AND tx.speed_gbps  = ${parseFloat(spd)}` : ""}
          ${ff  ? `AND tx.form_factor = '${ff.replace(/'/g,"''")}'` : ""}
        GROUP BY v.id, v.name, v.type, t.total
        ORDER BY sku_count DESC
        LIMIT 30
      `),

      // Momentum: compare last 30d vs prior 30d SKU count per vendor
      pool.query(`
        WITH cur AS (
          SELECT source_vendor_id, COUNT(DISTINCT transceiver_id)::int AS sku_count
          FROM price_observations po
          JOIN transceivers t ON t.id = po.transceiver_id
          WHERE po.time >= NOW() - INTERVAL '30 days'
            AND po.price > 0 AND COALESCE(po.is_anomalous, false) = false
            ${spd ? `AND t.speed_gbps  = ${parseFloat(spd)}` : ""}
            ${ff  ? `AND t.form_factor = '${ff.replace(/'/g,"''")}'` : ""}
          GROUP BY source_vendor_id
        ),
        prior AS (
          SELECT source_vendor_id, COUNT(DISTINCT transceiver_id)::int AS sku_count
          FROM price_observations po
          JOIN transceivers t ON t.id = po.transceiver_id
          WHERE po.time >= NOW() - INTERVAL '60 days'
            AND po.time <  NOW() - INTERVAL '30 days'
            AND po.price > 0 AND COALESCE(po.is_anomalous, false) = false
            ${spd ? `AND t.speed_gbps  = ${parseFloat(spd)}` : ""}
            ${ff  ? `AND t.form_factor = '${ff.replace(/'/g,"''")}'` : ""}
          GROUP BY source_vendor_id
        )
        SELECT
          v.name AS vendor_name, v.id::text AS vendor_id,
          c.sku_count AS current_skus,
          COALESCE(p.sku_count, 0) AS prior_skus,
          (c.sku_count - COALESCE(p.sku_count, 0)) AS delta_skus,
          CASE
            WHEN COALESCE(p.sku_count, 0) = 0 THEN NULL
            ELSE ROUND(((c.sku_count - p.sku_count)::numeric / p.sku_count::numeric) * 100, 1)
          END AS delta_pct
        FROM cur c
        JOIN vendors v ON v.id = c.source_vendor_id
        LEFT JOIN prior p ON p.source_vendor_id = c.source_vendor_id
        ORDER BY delta_skus DESC
        LIMIT 20
      `),
    ]);

    // Compute share % per week for chart (normalize across vendors per week)
    const weekTotals = new Map<string, number>();
    for (const row of weekly.rows) {
      const k = row.week;
      weekTotals.set(k, (weekTotals.get(k) || 0) + row.sku_count);
    }
    const weeklyWithShare = weekly.rows.map(r => ({
      ...r,
      share_pct: weekTotals.get(r.week)
        ? Math.round((r.sku_count / weekTotals.get(r.week)!) * 1000) / 10
        : 0,
    }));

    res.json({
      success: true,
      filters: { days, speed_gbps: spd || null, form_factor: ff || null },
      weekly_trend: weeklyWithShare,
      current_share: current.rows,
      momentum: momentum.rows,
    });
  } catch (err) {
    res.status(500).json({ success: false, error: String(err) });
  }
});

// GET /api/vendors/intelligence — per-vendor price + SKU market stats (last 30d)
vendorRouter.get("/intelligence", async (_req: Request, res: Response) => {
  try {
    const result = await pool.query(`
      SELECT
        v.id,
        v.name,
        v.type,
        v.website,
        COUNT(DISTINCT po.transceiver_id)::int                  AS sku_count,
        COUNT(*)::int                                        AS price_obs,
        ROUND(AVG(po.price)::numeric, 2)                        AS avg_price,
        ROUND(MIN(po.price)::numeric, 2)                        AS min_price,
        ROUND(MAX(po.price)::numeric, 2)                        AS max_price,
        MAX(po.time)                                             AS last_seen,
        (SELECT currency FROM price_observations
           WHERE source_vendor_id = v.id
           ORDER BY time DESC LIMIT 1)                           AS currency
      FROM vendors v
      LEFT JOIN price_observations po
        ON po.source_vendor_id = v.id
       AND po.time > NOW() - INTERVAL '30 days'
       AND po.price > 0
       AND COALESCE(po.is_anomalous, false) = false
      GROUP BY v.id, v.name, v.type, v.website
      HAVING COUNT(DISTINCT po.transceiver_id) > 0
      ORDER BY COUNT(DISTINCT po.transceiver_id) DESC
      LIMIT 60
    `);
    res.json({ success: true, data: result.rows });
  } catch (err) {
    res.status(500).json({ success: false, error: String(err) });
  }
});
