import { pool, markDetailsVerified, recordVerificationEvidence } from "./db";

const EXCLUDED_CATEGORIES = [
  "NonTransceiver",
  "Accessory",
  "Adapter / Converter",
  "Switch / Media Converter",
  "Switch / Network Infrastructure",
  "NIC / Adapter",
  "Mux / Passive Optical",
  "Product Family",
  "Loopback / Test Module",
];

type Candidate = {
  id: string;
  vendorName: string;
  partNumber: string;
  productUrl: string | null;
  formFactor: string | null;
  speedGbps: string | number | null;
  reachLabel: string | null;
  fiberType: string | null;
};

function inferSpeed(partNumber: string): { speed: string; speedGbps: number; rule: string } | null {
  const pn = partNumber.toUpperCase();
  const compact = pn.replace(/[^A-Z0-9]+/g, "-");

  const rules: Array<[RegExp, string, number, string]> = [
    [/\b(800G|800GE|800GBE)\b|JCO800|8X100G/, "800G", 800, "800G token"],
    [/\b(400G|400GE|400GBE|400ZR)\b|JCO400|4X100G/, "400G", 400, "400G token"],
    [/\b(200G|200GE|200GBE)\b|2X100G/, "200G", 200, "200G token"],
    [/\b(128GFC)\b/, "128G FC", 128, "128GFC token"],
    [/\b(100G|100GE|100GBE|CGE)\b|100GBASE|4X25G|2X50G|10X10G/, "100G", 100, "100G token"],
    [/\b(50G|50GE|50GBE)\b/, "50G", 50, "50G token"],
    [/\b(40G|40GE|40GBE)\b|40GBASE/, "40G", 40, "40G token"],
    [/\b(32GFC)\b/, "32G FC", 32, "32GFC token"],
    [/\b(25G|25GE|25GBE)\b|25GBASE/, "25G", 25, "25G token"],
    [/\b(16GFC)\b/, "16G FC", 16, "16GFC token"],
    [/\b(10G|10GE|10GBE)\b|10GBASE|SFP10G|XFP-10GE/, "10G", 10, "10G token"],
    [/\b(2[.-]?5G|2[.-]?5GE|2[.-]?5GBE)\b/, "2.5G", 2.5, "2.5G token"],
    [/\b(1G|1GE|1000BASE)\b|CTP-SFP-1GE|SFP-GE|GLC-(SX|LX|LH|ZX|EX|BX|TE|T)\b/, "1G", 1, "1G token"],
  ];

  for (const [regex, speed, speedGbps, rule] of rules) {
    if (regex.test(compact) || regex.test(pn)) {
      return { speed, speedGbps, rule };
    }
  }
  return null;
}

async function main(): Promise<void> {
  const vendorFilter = (process.env["PART_DETAILS_VENDOR"] || "").trim();
  const limit = parseInt(process.env["PART_DETAILS_LIMIT"] || "1000", 10);
  const apply = process.env["PART_DETAILS_APPLY"] === "1";
  const vendorNames = vendorFilter.split(",").map((v) => v.trim()).filter(Boolean);

  const vendorWhere = vendorNames.length > 0 ? "AND v.name = ANY($3)" : "";
  const params: unknown[] = [EXCLUDED_CATEGORIES, limit];
  if (vendorNames.length > 0) params.push(vendorNames);

  const result = await pool.query<Candidate>(
    `SELECT t.id,
            v.name AS "vendorName",
            t.part_number AS "partNumber",
            t.product_page_url AS "productUrl",
            t.form_factor AS "formFactor",
            t.speed_gbps AS "speedGbps",
            t.reach_label AS "reachLabel",
            t.fiber_type AS "fiberType"
     FROM transceivers t
     JOIN vendors v ON v.id = t.vendor_id
     WHERE COALESCE(t.category, '') <> ALL($1)
       AND COALESCE(t.data_confidence, 'unknown') != 'garbage'
       AND COALESCE(t.part_number, '') != ''
       AND COALESCE(t.form_factor, '') != ''
       AND COALESCE(t.reach_label, '') != ''
       AND COALESCE(t.fiber_type, '') != ''
       AND (t.speed_gbps IS NULL OR t.speed_gbps = 0 OR COALESCE(t.details_verified, false) = false)
       ${vendorWhere}
     ORDER BY v.name, t.part_number
     LIMIT $2`,
    params,
  );

  let candidates = 0;
  let updated = 0;
  let details = 0;
  let skipped = 0;

  console.log("=== Part-number details verifier ===", { vendorNames, limit, apply, count: result.rows.length });

  for (const row of result.rows) {
    const inferred = inferSpeed(row.partNumber);
    if (!inferred) {
      skipped++;
      continue;
    }
    candidates++;
    const currentSpeed = Number(row.speedGbps || 0);
    const shouldUpdateSpeed = currentSpeed === 0 || currentSpeed === null;
    if (!apply) {
      console.log("dry-run part details", {
        vendor: row.vendorName,
        partNumber: row.partNumber,
        currentSpeed,
        inferred,
        canMarkDetails: Boolean(row.formFactor && row.reachLabel && row.fiberType),
      });
      continue;
    }

    if (shouldUpdateSpeed) {
      await pool.query(
        `UPDATE transceivers
         SET speed = $2,
             speed_gbps = $3,
             updated_at = NOW()
         WHERE id = $1`,
        [row.id, inferred.speed, inferred.speedGbps],
      );
      updated++;
    }

    const marked = await markDetailsVerified({
      transceiverId: row.id,
      sourceUrl: row.productUrl || undefined,
    });
    if (marked) details++;

    await recordVerificationEvidence({
      transceiverId: row.id,
      verificationType: "details",
      sourceUrl: row.productUrl || undefined,
      evidenceValue: {
        rule: "part_number_speed_inference",
        partNumber: row.partNumber,
        speed: inferred.speed,
        speedGbps: inferred.speedGbps,
        inferenceRule: inferred.rule,
      },
      robotName: "verify:part-number-details",
      confidence: 0.95,
    });
  }

  console.log("Part-number details verifier complete", { candidates, updated, details, skipped, apply });
}

if (require.main === module) {
  main()
    .then(() => pool.end())
    .catch((err) => {
      console.error("Fatal:", err);
      pool.end();
      process.exit(1);
    });
}
