/**
 * WS1: Switch → Flexoptix Transceiver Finder
 *
 * "Customer has a Cisco Nexus 93180YC-FX3 — which Flexoptix transceivers fit?"
 */
import { Router } from "express";
import { pool } from "../db/client";

export const finderRouter = Router();

/**
 * GET /api/finder?switch=<model>&speed=&form_factor=
 *
 * Finds Flexoptix-compatible transceivers for a given switch model.
 * If no direct Flexoptix match, shows generic compatible transceivers
 * with a note about Flexoptix FlexBox coding capability.
 */
finderRouter.get("/", async (req, res) => {
  try {
    const { switch: switchQuery, speed, form_factor, limit = "20" } = req.query;

    if (!switchQuery) {
      return res.status(400).json({ error: "Parameter 'switch' is required" });
    }

    // Step 1: Find the switch — try multiple search strategies
    const q = String(switchQuery);
    // Normalized form: remove hyphens/spaces for fuzzy match (sg350-28 → sg35028)
    const qNorm = q.replace(/[\s\-_]/g, "");

    const switchResult = await pool.query(
      `SELECT sw.id, sw.model, sw.series, sw.ports_config, sw.max_speed_gbps,
              sw.system_type, sw.is_linecard, sw.chassis_model, sw.slot_type,
              sw.flexbox_compat_mode, sw.flexbox_notes, sw.description,
              sw.switching_capacity_tbps, sw.total_ports, sw.category,
              sw.lifecycle_status, sw.features, sw.use_cases,
              v.name AS vendor_name, sw.image_url, sw.datasheet_r2_key
       FROM switches sw
       JOIN vendors v ON sw.vendor_id = v.id
       WHERE sw.model ILIKE $1
          OR sw.model ILIKE '%' || $1 || '%'
          OR REPLACE(REPLACE(sw.model, '-', ''), ' ', '') ILIKE '%' || $2 || '%'
          OR sw.search_vector @@ plainto_tsquery('english', $3)
       ORDER BY
         CASE WHEN sw.model ILIKE $1 THEN 0
              WHEN sw.model ILIKE $1 || '%' THEN 1
              WHEN REPLACE(REPLACE(sw.model, '-', ''), ' ', '') ILIKE $2 || '%' THEN 2
              ELSE 3 END
       LIMIT 5`,
      [q, qNorm, q.replace(/[^\w\s]/g, " ")]
    );

    if (switchResult.rows.length === 0) {
      // Try one more time with individual tokens
      const tokens = q.split(/[\s\-_]+/).filter((t) => t.length >= 3);
      let fallbackResult = { rows: [] as any[] };
      if (tokens.length > 0) {
        fallbackResult = await pool.query(
          `SELECT sw.id, sw.model, sw.series, sw.ports_config, sw.max_speed_gbps,
                  v.name AS vendor_name, sw.image_url, sw.datasheet_r2_key
           FROM switches sw JOIN vendors v ON sw.vendor_id = v.id
           WHERE ${tokens.map((_, i) => `sw.model ILIKE '%' || $${i + 1} || '%'`).join(" AND ")}
           LIMIT 5`,
          tokens
        );
      }
      if (fallbackResult.rows.length === 0) {
        return res.status(404).json({
          error: `Switch "${q}" not found in the database`,
          suggestion: `Try a partial model name, e.g. "${tokens[0] || q.substring(0, 6)}" — or check spelling. Available: Cisco Nexus, Arista, Juniper QFX, Edgecore, Mellanox.`
        });
      }
      switchResult.rows.push(...fallbackResult.rows);
    }

    const sw = switchResult.rows[0];

    // Step 2: Find compatible transceivers via compatibility table
    let compatSql = `
      SELECT
        t.id, t.slug, t.form_factor, t.speed, t.speed_gbps, t.reach_label, t.reach_meters,
        t.fiber_type, t.wavelengths, t.connector, t.power_consumption_w,
        t.image_url, t.image_r2_key, t.part_number, t.product_page_url,
        -- Verification tags
        t.price_verified, t.price_verified_eur, t.price_verified_url, t.price_verified_at,
        t.image_verified, t.details_verified, t.fully_verified, t.fully_verified_at,
        tv.name AS transceiver_vendor,
        tv.type AS vendor_type,
        c.status AS compat_status,
        c.firmware_min,
        c.verified_by,
        c.notes AS compat_notes,
        -- Latest price (verified preferred)
        COALESCE(t.price_verified_eur,
          (SELECT po.price FROM price_observations po WHERE po.transceiver_id = t.id ORDER BY po.time DESC LIMIT 1)
        ) AS latest_price,
        CASE WHEN t.price_verified_eur IS NOT NULL THEN 'EUR'
          ELSE (SELECT po.currency FROM price_observations po WHERE po.transceiver_id = t.id ORDER BY po.time DESC LIMIT 1)
        END AS latest_currency,
        (SELECT po.stock_level FROM price_observations po WHERE po.transceiver_id = t.id ORDER BY po.time DESC LIMIT 1) AS stock_level,
        -- Flexoptix mapping
        fpm.flexoptix_sku,
        fpm.flexoptix_url,
        fpm.flexoptix_price_eur,
        fpm.match_type AS flexoptix_match
      FROM compatibility c
      JOIN transceivers t ON c.transceiver_id = t.id
      JOIN vendors tv ON t.vendor_id = tv.id
      LEFT JOIN flexoptix_product_map fpm ON (
        fpm.form_factor = t.form_factor
        AND fpm.speed_gbps = t.speed_gbps
        AND (fpm.reach_label = t.reach_label OR fpm.reach_label IS NULL)
      )
      WHERE c.switch_id = $1 AND c.status = 'compatible'
    `;
    const params: any[] = [sw.id];
    let idx = 2;

    if (speed) {
      compatSql += ` AND t.speed_gbps = $${idx}`;
      params.push(parseFloat(speed as string));
      idx++;
    }
    if (form_factor) {
      compatSql += ` AND t.form_factor = $${idx}`;
      params.push(form_factor);
      idx++;
    }

    compatSql += ` ORDER BY t.speed_gbps DESC, t.reach_meters ASC LIMIT $${idx}`;
    params.push(parseInt(limit as string));

    const compatResult = await pool.query(compatSql, params);

    // Step 3: Group results by speed class
    const bySpeed: Record<string, any[]> = {};
    for (const row of compatResult.rows) {
      const key = `${row.speed_gbps}G ${row.form_factor}`;
      if (!bySpeed[key]) bySpeed[key] = [];
      bySpeed[key].push({
        ...row,
        flexoptix_available: !!row.flexoptix_sku,
        flexbox_codable: true, // All Flexoptix modules are FlexBox-codable
        buy_url: row.flexoptix_url || `https://www.flexoptix.net/en/catalogsearch/result/?q=${encodeURIComponent(row.form_factor + ' ' + row.speed_gbps + 'G ' + row.reach_label)}`,
      });
    }

    // Step 4: Extract port types from switch for "what can this switch accept?"
    const portTypes = sw.ports_config || {};

    // Linecard system: fetch sibling linecards if this is a chassis or linecard
    let linecards: any[] = [];
    if (sw.is_linecard && sw.chassis_model) {
      const siblingResult = await pool.query(
        `SELECT sw2.model, sw2.total_ports, sw2.max_speed_gbps, sw2.switching_capacity_tbps, sw2.features, sw2.slot_type
         FROM switches sw2
         WHERE sw2.chassis_model = $1 AND sw2.id != $2 AND sw2.is_linecard = true
         ORDER BY sw2.model LIMIT 20`,
        [sw.chassis_model, sw.id]
      );
      linecards = siblingResult.rows;
    } else if (!sw.is_linecard && sw.system_type === "modular") {
      const lcResult = await pool.query(
        `SELECT sw2.model, sw2.total_ports, sw2.max_speed_gbps, sw2.switching_capacity_tbps, sw2.features, sw2.slot_type
         FROM switches sw2
         WHERE sw2.chassis_model = $1 AND sw2.is_linecard = true
         ORDER BY sw2.model LIMIT 20`,
        [sw.series]
      );
      linecards = lcResult.rows;
    }

    res.json({
      switch: {
        id: sw.id,
        model: sw.model,
        series: sw.series,
        vendor: sw.vendor_name,
        category: sw.category,
        description: sw.description,
        max_speed_gbps: sw.max_speed_gbps,
        switching_capacity_tbps: sw.switching_capacity_tbps ? parseFloat(sw.switching_capacity_tbps) : null,
        total_ports: sw.total_ports,
        features: sw.features || [],
        use_cases: sw.use_cases || [],
        lifecycle_status: sw.lifecycle_status,
        ports: portTypes,
        image_url: sw.image_url,
        // Linecard / Modular system info
        system_type: sw.system_type || "fixed",
        is_linecard: sw.is_linecard === true,
        chassis_model: sw.chassis_model || null,
        slot_type: sw.slot_type || null,
        linecards: linecards,
        // Flexbox programming info
        flexbox_compat_mode: sw.flexbox_compat_mode || null,
        flexbox_notes: sw.flexbox_notes || null,
      },
      compatible_transceivers: compatResult.rows.map(r => ({
        id: r.id,
        slug: r.slug,
        part_number: r.part_number,
        form_factor: r.form_factor,
        speed: r.speed,
        speed_gbps: r.speed_gbps,
        reach: r.reach_label,
        fiber_type: r.fiber_type,
        connector: r.connector,
        vendor: r.transceiver_vendor,
        vendor_type: r.vendor_type,
        image_url: r.image_url,
        product_page_url: r.product_page_url,
        compat_status: r.compat_status,
        firmware_min: r.firmware_min,
        // Pricing
        price: r.latest_price ? parseFloat(r.latest_price) : null,
        currency: r.latest_currency,
        stock: r.stock_level,
        // Verification tags
        price_verified: r.price_verified === true,
        price_verified_eur: r.price_verified_eur ? parseFloat(r.price_verified_eur) : null,
        price_verified_url: r.price_verified_url || null,
        price_verified_at: r.price_verified_at || null,
        image_verified: r.image_verified === true,
        details_verified: r.details_verified === true,
        fully_verified: r.fully_verified === true,
        fully_verified_at: r.fully_verified_at || null,
        // Flexoptix
        flexoptix_sku: r.flexoptix_sku,
        flexoptix_url: r.flexoptix_url,
        flexoptix_price_eur: r.flexoptix_price_eur ? parseFloat(r.flexoptix_price_eur) : null,
        flexoptix_match: r.flexoptix_match,
        flexbox_codable: true,
        buy_url: r.flexoptix_url || `https://www.flexoptix.net/en/catalogsearch/result/?q=${encodeURIComponent(r.form_factor + ' ' + r.speed_gbps + 'G ' + r.reach_label)}`,
      })),
      by_speed_class: bySpeed,
      total: compatResult.rowCount,
      flexoptix_note: "All Flexoptix transceivers support FlexBox coding for OEM compatibility.",
    });
  } catch (err) {
    console.error("Finder error:", err);
    res.status(500).json({ error: "Internal server error" });
  }
});

/**
 * GET /api/finder/suggest?q=<free text>
 *
 * Free-text query: "100G LR4 for Cisco Nexus" → suggests switch + transceiver combos
 */
finderRouter.get("/suggest", async (req, res) => {
  try {
    const { q } = req.query;
    if (!q) return res.status(400).json({ error: "Parameter 'q' is required" });

    // Extract speed, form factor, vendor hints from query
    const queryStr = (q as string).toLowerCase();
    let speed: number | null = null;
    let vendor: string | null = null;
    let reach: string | null = null;

    // Speed detection
    const speedMatch = queryStr.match(/(\d+)\s*g\b/i);
    if (speedMatch) speed = parseInt(speedMatch[1]!);

    // Reach detection
    if (queryStr.includes('sr')) reach = 'SR';
    else if (queryStr.includes('lr')) reach = 'LR';
    else if (queryStr.includes('er')) reach = 'ER';
    else if (queryStr.includes('zr')) reach = 'ZR';
    else if (queryStr.includes('dr')) reach = 'DR';

    // Vendor detection
    const vendorPatterns: [RegExp, string][] = [
      [/cisco|nexus|catalyst/i, 'Cisco'],
      [/juniper|qfx|ex\d{4}/i, 'Juniper'],
      [/arista|dcs-/i, 'Arista'],
      [/dell|powerswitch/i, 'Dell'],
      [/hpe|aruba/i, 'HPE'],
    ];
    for (const [pattern, name] of vendorPatterns) {
      if (pattern.test(queryStr)) { vendor = name; break; }
    }

    // Search switches matching the query
    const switches = await pool.query(
      `SELECT sw.id, sw.model, sw.series, sw.max_speed_gbps, v.name AS vendor_name
       FROM switches sw JOIN vendors v ON sw.vendor_id = v.id
       WHERE sw.search_vector @@ plainto_tsquery('english', $1)
         ${vendor ? `AND v.name ILIKE '%' || $2 || '%'` : ''}
       ORDER BY sw.max_speed_gbps DESC LIMIT 10`,
      vendor ? [q, vendor] : [q]
    );

    // Search transceivers matching speed/reach
    let tcvrSql = `SELECT t.id, t.slug, t.form_factor, t.speed_gbps, t.reach_label, t.fiber_type,
       tv.name AS vendor, t.image_url
       FROM transceivers t JOIN vendors v ON t.vendor_id = v.id JOIN vendors tv ON t.vendor_id = tv.id
       WHERE 1=1`;
    const tcvrParams: any[] = [];
    let tidx = 1;
    if (speed) { tcvrSql += ` AND t.speed_gbps = $${tidx}`; tcvrParams.push(speed); tidx++; }
    if (reach) { tcvrSql += ` AND t.reach_label ILIKE $${tidx}`; tcvrParams.push(reach + '%'); tidx++; }
    tcvrSql += ` ORDER BY t.speed_gbps DESC LIMIT 10`;

    const transceivers = await pool.query(tcvrSql, tcvrParams);

    res.json({
      query: q,
      parsed: { speed, vendor, reach },
      switches: switches.rows,
      transceivers: transceivers.rows,
      tip: "Use GET /api/finder?switch=<model> for detailed compatibility results",
    });
  } catch (err) {
    console.error("Suggest error:", err);
    res.status(500).json({ error: "Internal server error" });
  }
});
