/**
 * GAO Tek Detail Page Verifier
 *
 * Fetches GAO product pages that are already known real product URLs but still
 * lack details_verified, then extracts deterministic specs from title/meta/body.
 */
import * as cheerio from "cheerio";
import { pool, markDetailsVerified } from "../utils/db";
import { logger } from "../utils/logger";

const HEADERS = {
  "User-Agent": "Mozilla/5.0 (compatible; TIP-GAOTekDetailVerifier/1.0)",
  Accept: "text/html,application/xhtml+xml",
  "Accept-Language": "en-US,en;q=0.9",
};

interface Row {
  id: string;
  part_number: string;
  product_page_url: string;
}

function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function fetchHtml(url: string): Promise<string> {
  const resp = await fetch(url, {
    headers: HEADERS,
    signal: AbortSignal.timeout(25000),
  });
  if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
  return resp.text();
}

function compact(text: string): string {
  return text.replace(/\s+/g, " ").trim();
}

function parseSpeed(text: string): { speed: string; speedGbps: number; formFactor?: string } {
  const s = text.toUpperCase();
  if (/100\s*G|100G|100GE/.test(s)) return { speed: "100G", speedGbps: 100, formFactor: /CFP/.test(s) ? "CFP" : "QSFP28" };
  if (/40\s*G|40G|40GE/.test(s)) return { speed: "40G", speedGbps: 40, formFactor: "QSFP+" };
  if (/32\s*G|32G/.test(s)) return { speed: "32G", speedGbps: 32, formFactor: "SFP+" };
  if (/25\s*G|25G/.test(s)) return { speed: "25G", speedGbps: 25, formFactor: "SFP28" };
  if (/10\s*G|10G|11\.3\s*GB/.test(s)) return { speed: "10G", speedGbps: 10, formFactor: /XFP/.test(s) ? "XFP" : "SFP+" };
  if (/3\.125\s*G/.test(s)) return { speed: "3.125G", speedGbps: 3.125, formFactor: "SFP" };
  if (/2\.5\s*G/.test(s)) return { speed: "2.5G", speedGbps: 2.5, formFactor: "SFP" };
  if (/1\.25\s*G|1G|1000BASE/.test(s)) return { speed: "1G", speedGbps: 1, formFactor: "SFP" };
  return { speed: "Unknown", speedGbps: 0 };
}

function parseReach(text: string): { label: string; meters: number } | null {
  const matches = [...text.matchAll(/\b(\d+(?:\.\d+)?)\s*(km|m)\b/gi)]
    .map((m) => ({ value: Number(m[1]), unit: m[2].toLowerCase() }))
    .filter((m) => m.value > 0);

  if (matches.length > 0) {
    const meters = matches.map((m) => m.unit === "km" ? Math.round(m.value * 1000) : Math.round(m.value));
    const maxMeters = Math.max(...meters);
    return {
      label: maxMeters >= 1000 ? `${Math.round(maxMeters / 1000)}km` : `${maxMeters}m`,
      meters: maxMeters,
    };
  }

  const s = text.toUpperCase();
  if (s.includes("ZR")) return { label: "80km", meters: 80000 };
  if (s.includes("ER")) return { label: "40km", meters: 40000 };
  if (s.includes("LR")) return { label: "10km", meters: 10000 };
  if (s.includes("FR")) return { label: "2km", meters: 2000 };
  if (s.includes("DR")) return { label: "500m", meters: 500 };
  if (s.includes("SR")) return { label: "100m", meters: 100 };
  return null;
}

function parseFiber(text: string): string {
  if (/single[- ]?mode|\bSMF\b|9\s*(?:µm|um)|1310\s*nm|1550\s*nm|CWDM|DWDM|BIDI/i.test(text)) return "SMF";
  if (/multi[- ]?mode|\bMMF\b|850\s*nm|OM3|OM4/i.test(text)) return "MMF";
  if (/copper|RJ-?45|1000BASE-T|10GBASE-T|DAC|twinax/i.test(text)) return "Copper";
  return "";
}

function parseWavelengths(text: string): string {
  const values = [...text.matchAll(/\b(\d{3,4})\s*nm\b/gi)]
    .map((m) => m[1])
    .filter((v, i, a) => a.indexOf(v) === i)
    .slice(0, 8);
  return values.join("/");
}

function extractText(html: string): string {
  const $ = cheerio.load(html);
  const title = $(".product_title, h1").first().text();
  const meta = $("meta[property='og:description']").attr("content") ||
    $("meta[name='description']").attr("content") ||
    "";
  const body = $(".woocommerce-product-details__short-description, .summary, .woocommerce-Tabs-panel, .product-tabs-wrapper")
    .text();
  return compact(`${title} ${meta} ${body}`);
}

async function loadRows(limit: number): Promise<Row[]> {
  const result = await pool.query<Row>(`
    SELECT t.id, t.part_number, t.product_page_url
    FROM transceivers t
    JOIN vendors v ON v.id = t.vendor_id
    WHERE v.name = 'GAO Tek'
      AND COALESCE(t.details_verified, false) = false
      AND COALESCE(t.category, '') != 'NonTransceiver'
      AND t.product_page_url LIKE 'https://gaotek.com/product/%'
    ORDER BY t.image_verified DESC, t.part_number
    LIMIT $1
  `, [limit]);
  return result.rows;
}

export async function verifyGaoTekDetailPages(): Promise<void> {
  const limit = Math.max(1, parseInt(process.env.GAOTEK_DETAIL_LIMIT || "500", 10));
  const rows = await loadRows(limit);
  logger.info("=== GAO Tek detail verifier ===", { rows: rows.length, limit });

  let updated = 0;
  let verified = 0;
  let skipped = 0;
  let errors = 0;

  for (const row of rows) {
    try {
      const html = await fetchHtml(row.product_page_url);
      const text = extractText(html);
      const reach = parseReach(text);
      const fiber = parseFiber(text);
      const speed = parseSpeed(text);
      const wavelengths = parseWavelengths(text);

      if (!reach || !fiber || speed.speedGbps <= 0) {
        skipped++;
        await sleep(250);
        continue;
      }

      await pool.query(`
        UPDATE transceivers
        SET form_factor = CASE WHEN form_factor IS NULL OR form_factor = '' OR form_factor = 'SFP+' THEN COALESCE($2, form_factor) ELSE form_factor END,
            speed = CASE WHEN speed IS NULL OR speed = '' OR speed = 'Unknown' THEN $3 ELSE speed END,
            speed_gbps = CASE WHEN speed_gbps IS NULL OR speed_gbps = 0 THEN $4 ELSE speed_gbps END,
            reach_label = CASE WHEN reach_label IS NULL OR reach_label = '' THEN $5 ELSE reach_label END,
            reach_meters = CASE WHEN reach_meters IS NULL OR reach_meters = 0 THEN $6 ELSE reach_meters END,
            fiber_type = CASE WHEN fiber_type IS NULL OR fiber_type = '' THEN $7 ELSE fiber_type END,
            wavelengths = CASE WHEN wavelengths IS NULL OR wavelengths = '' THEN NULLIF($8, '') ELSE wavelengths END,
            updated_at = NOW()
        WHERE id = $1
      `, [
        row.id,
        speed.formFactor || null,
        speed.speed,
        speed.speedGbps,
        reach.label,
        reach.meters,
        fiber,
        wavelengths,
      ]);
      updated++;

      if (await markDetailsVerified({ transceiverId: row.id, sourceUrl: row.product_page_url })) {
        verified++;
      }
    } catch (err) {
      errors++;
      logger.warn("GAO Tek detail page failed", {
        partNumber: row.part_number,
        url: row.product_page_url,
        error: (err as Error).message,
      });
    }
    await sleep(250);
  }

  logger.info("GAO Tek detail verifier complete", { updated, verified, skipped, errors });
}

if (require.main === module) {
  verifyGaoTekDetailPages()
    .then(() => pool.end())
    .catch((err) => {
      logger.error("GAO Tek detail verifier failed", { error: (err as Error).message });
      pool.end();
      process.exit(1);
    });
}
