/**
 * Manual Review API — Transceiver Equivalence Review Queue
 *
 * GET  /api/review/equivalences           — list (filter by status)
 * GET  /api/review/equivalences/stats     — pending/approved/rejected counts
 * POST /api/review/equivalences/:id/approve — approve + set competitor_verified
 * POST /api/review/equivalences/:id/reject  — reject with optional reason
 * PATCH /api/review/equivalences/:id        — edit match_notes
 * POST /api/review/run-matcher             — trigger equivalence job immediately
 */
import { Router, Request, Response } from "express";
import { pool } from "../db/client";

/** Promote to fully_verified if all 4 flags are set — shared logic */
async function checkAndSetFullyVerified(transceiverId: string): Promise<boolean> {
  const result = await pool.query(
    `UPDATE transceivers
     SET fully_verified = true,
         fully_verified_at = COALESCE(fully_verified_at, NOW())
     WHERE id = $1
       AND price_verified = true AND image_verified = true
       AND details_verified = true AND competitor_verified = true
       AND (fully_verified IS NULL OR fully_verified = false)
     RETURNING id`,
    [transceiverId]
  );
  return (result.rowCount ?? 0) > 0;
}

export const reviewRouter = Router();

// ── GET /api/review/equivalences ──────────────────────────────────────────────
reviewRouter.get("/equivalences", async (req: Request, res: Response) => {
  const status = (req.query.status as string) || "pending";
  const page   = Math.max(1, parseInt(req.query.page as string, 10) || 1);
  const limit  = Math.min(100, parseInt(req.query.limit as string, 10) || 50);
  const offset = (page - 1) * limit;

  const validStatuses = ["pending", "approved", "rejected", "auto_approved", "all", "needs_research"];
  if (!validStatuses.includes(status)) {
    res.status(400).json({ success: false, error: "Invalid status filter" });
    return;
  }

  let where: string;
  let params: unknown[];
  let limitIdx: number;
  let offsetIdx: number;
  if (status === "all") {
    where = "";
    params = [limit, offset];
    limitIdx = 1; offsetIdx = 2;
  } else if (status === "needs_research") {
    where = `WHERE eq.status IN ('approved','auto_approved') AND eq.re_research_due_at IS NOT NULL AND eq.re_research_due_at <= NOW()`;
    params = [limit, offset];
    limitIdx = 1; offsetIdx = 2;
  } else {
    where = `WHERE eq.status = $1`;
    params = [status, limit, offset];
    limitIdx = 2; offsetIdx = 3;
  }

  const rows = await pool.query(`
    SELECT
      eq.id,
      eq.confidence,
      eq.match_basis,
      eq.match_notes,
      eq.status,
      eq.reviewed_by,
      eq.reviewed_at,
      eq.reject_reason,
      eq.re_research_due_at,
      eq.re_researched_at,
      eq.created_at,
      eq.updated_at,
      -- Flexoptix transceiver
      fx.id            AS fx_id,
      fx.part_number   AS fx_part_number,
      fx.standard_name AS fx_standard_name,
      fx.form_factor   AS fx_form_factor,
      fx.speed         AS fx_speed,
      fx.speed_gbps    AS fx_speed_gbps,
      fx.fiber_type    AS fx_fiber_type,
      fx.reach_meters  AS fx_reach_meters,
      fx.reach_label   AS fx_reach_label,
      fx.wavelengths   AS fx_wavelengths,
      fx.connector     AS fx_connector,
      fx.product_page_url AS fx_url,
      fxv.name         AS fx_vendor,
      -- Competitor transceiver
      cp.id            AS cp_id,
      cp.part_number   AS cp_part_number,
      cp.standard_name AS cp_standard_name,
      cp.form_factor   AS cp_form_factor,
      cp.speed         AS cp_speed,
      cp.speed_gbps    AS cp_speed_gbps,
      cp.fiber_type    AS cp_fiber_type,
      cp.reach_meters  AS cp_reach_meters,
      cp.reach_label   AS cp_reach_label,
      cp.wavelengths   AS cp_wavelengths,
      cp.connector     AS cp_connector,
      cp.product_page_url AS cp_url,
      cpv.name         AS cp_vendor,
      -- Latest competitor price
      (SELECT po.price FROM price_observations po
       WHERE po.transceiver_id = cp.id
         AND po.time > NOW() - INTERVAL '30 days'
       ORDER BY po.time DESC LIMIT 1)  AS cp_latest_price,
      (SELECT po.currency FROM price_observations po
       WHERE po.transceiver_id = cp.id
         AND po.time > NOW() - INTERVAL '30 days'
       ORDER BY po.time DESC LIMIT 1)  AS cp_latest_currency
    FROM transceiver_equivalences eq
    JOIN transceivers fx  ON fx.id  = eq.flexoptix_id
    JOIN vendors fxv      ON fxv.id = fx.vendor_id
    JOIN transceivers cp  ON cp.id  = eq.competitor_id
    JOIN vendors cpv      ON cpv.id = cp.vendor_id
    ${where}
    ORDER BY eq.confidence DESC, eq.created_at DESC
    LIMIT $${limitIdx} OFFSET $${offsetIdx}
  `, params);

  const countResult = await pool.query(
    `SELECT COUNT(*) FROM transceiver_equivalences eq ${where}`,
    (status === "all" || status === "needs_research") ? [] : [status]
  );

  res.json({
    success: true,
    data: rows.rows,
    total: parseInt(countResult.rows[0].count, 10),
    page,
    limit,
  });
});

// ── GET /api/review/equivalences/stats ────────────────────────────────────────
reviewRouter.get("/equivalences/stats", async (_req: Request, res: Response) => {
  const result = await pool.query(`
    SELECT
      SUM(CASE WHEN status = 'pending'       THEN 1 ELSE 0 END) AS pending,
      SUM(CASE WHEN status = 'approved'      THEN 1 ELSE 0 END) AS approved,
      SUM(CASE WHEN status = 'auto_approved' THEN 1 ELSE 0 END) AS auto_approved,
      SUM(CASE WHEN status = 'rejected'      THEN 1 ELSE 0 END) AS rejected,
      SUM(CASE WHEN status IN ('approved','auto_approved')
               AND re_research_due_at IS NOT NULL
               AND re_research_due_at <= NOW()        THEN 1 ELSE 0 END) AS needs_research,
      COUNT(*)                                                            AS total
    FROM transceiver_equivalences
  `);

  const row = result.rows[0];
  res.json({
    success: true,
    stats: {
      pending:        parseInt(row.pending,         10) || 0,
      approved:       parseInt(row.approved,        10) || 0,
      auto_approved:  parseInt(row.auto_approved,   10) || 0,
      rejected:       parseInt(row.rejected,        10) || 0,
      needs_research: parseInt(row.needs_research,  10) || 0,
      total:          parseInt(row.total,           10) || 0,
    },
  });
});

// ── POST /api/review/equivalences/:id/approve ─────────────────────────────────
reviewRouter.post("/equivalences/:id/approve", async (req: Request, res: Response) => {
  const { id } = req.params;
  const reviewer = (req.body as { reviewer?: string }).reviewer || "manual";

  // Fetch the equivalence to get flexoptix_id
  const eq = await pool.query(
    `SELECT * FROM transceiver_equivalences WHERE id = $1`,
    [id]
  );
  if (!eq.rows[0]) {
    res.status(404).json({ success: false, error: "Not found" });
    return;
  }

  const { flexoptix_id } = eq.rows[0] as { flexoptix_id: string };

  // Mark approved
  await pool.query(`
    UPDATE transceiver_equivalences
    SET status = 'approved', reviewed_by = $2, reviewed_at = NOW()
    WHERE id = $1
  `, [id, reviewer]);

  // Set competitor_verified on the Flexoptix transceiver
  await pool.query(`
    UPDATE transceivers
    SET competitor_verified = true,
        competitor_verified_at = NOW()
    WHERE id = $1
  `, [flexoptix_id]);

  // Promote to fully_verified if all 4 flags are now set
  const fullyVerifiedEarned = await checkAndSetFullyVerified(flexoptix_id);

  res.json({
    success: true,
    fully_verified_earned: fullyVerifiedEarned,
  });
});

// ── POST /api/review/equivalences/:id/reject ──────────────────────────────────
reviewRouter.post("/equivalences/:id/reject", async (req: Request, res: Response) => {
  const { id } = req.params;
  const { reason, reviewer } = req.body as { reason?: string; reviewer?: string };

  const result = await pool.query(`
    UPDATE transceiver_equivalences
    SET status = 'rejected',
        reject_reason = $2,
        reviewed_by   = $3,
        reviewed_at   = NOW()
    WHERE id = $1
    RETURNING id
  `, [id, reason || null, reviewer || "manual"]);

  if (!result.rowCount) {
    res.status(404).json({ success: false, error: "Not found" });
    return;
  }

  res.json({ success: true });
});

// ── PATCH /api/review/equivalences/:id ────────────────────────────────────────
reviewRouter.patch("/equivalences/:id", async (req: Request, res: Response) => {
  const { id } = req.params;
  const { match_notes } = req.body as { match_notes?: string };

  if (match_notes === undefined) {
    res.status(400).json({ success: false, error: "match_notes required" });
    return;
  }

  const result = await pool.query(`
    UPDATE transceiver_equivalences
    SET match_notes = $2, updated_at = NOW()
    WHERE id = $1
    RETURNING id
  `, [id, match_notes]);

  if (!result.rowCount) {
    res.status(404).json({ success: false, error: "Not found" });
    return;
  }

  res.json({ success: true });
});

// ── POST /api/review/equivalences/approve-all ─────────────────────────────────
// Approve ALL pending equivalences regardless of confidence.
// Low-confidence ones (< 0.73) get re_research_due_at = NOW() so the nightly
// re-research job will re-verify them one by one.
reviewRouter.post("/equivalences/approve-all", async (req: Request, res: Response) => {
  const reviewer = (req.body as { reviewer?: string }).reviewer || "approve-all";
  const RE_RESEARCH_THRESHOLD = 0.73;

  const candidates = await pool.query(`
    SELECT id, flexoptix_id, confidence FROM transceiver_equivalences WHERE status = 'pending'
  `);

  let approved = 0;
  let fullyVerified = 0;
  let scheduledReSearch = 0;

  for (const row of candidates.rows) {
    const needsReSearch = parseFloat(row.confidence) < RE_RESEARCH_THRESHOLD;
    await pool.query(`
      UPDATE transceiver_equivalences
      SET status             = 'approved',
          reviewed_by        = $2,
          reviewed_at        = NOW(),
          re_research_due_at = $3,
          re_researched_at   = NULL
      WHERE id = $1
    `, [row.id, reviewer, needsReSearch ? new Date() : null]);

    await pool.query(`
      UPDATE transceivers
      SET competitor_verified = true, competitor_verified_at = NOW()
      WHERE id = $1 AND competitor_verified = false
    `, [row.flexoptix_id]);

    const earned = await checkAndSetFullyVerified(row.flexoptix_id);
    if (earned) fullyVerified++;
    if (needsReSearch) scheduledReSearch++;
    approved++;
  }

  res.json({ success: true, approved, fully_verified_earned: fullyVerified, scheduled_re_research: scheduledReSearch });
});

// ── POST /api/review/equivalences/bulk-approve ────────────────────────────────
// Bulk-approve all pending equivalences with confidence >= threshold (default 0.73)
reviewRouter.post("/equivalences/bulk-approve", async (req: Request, res: Response) => {
  const threshold = Math.max(0, Math.min(1, parseFloat((req.body as { threshold?: string }).threshold as string) || 0.73));
  const reviewer  = (req.body as { reviewer?: string }).reviewer || "bulk-dashboard";

  // Fetch all pending records above threshold
  const candidates = await pool.query(`
    SELECT id, flexoptix_id
    FROM transceiver_equivalences
    WHERE status = 'pending' AND confidence >= $1
  `, [threshold]);

  let approved = 0;
  let fullyVerified = 0;

  for (const row of candidates.rows) {
    await pool.query(`
      UPDATE transceiver_equivalences
      SET status = 'approved', reviewed_by = $2, reviewed_at = NOW()
      WHERE id = $1
    `, [row.id, reviewer]);

    await pool.query(`
      UPDATE transceivers
      SET competitor_verified = true, competitor_verified_at = NOW()
      WHERE id = $1 AND competitor_verified = false
    `, [row.flexoptix_id]);

    const earned = await checkAndSetFullyVerified(row.flexoptix_id);
    if (earned) fullyVerified++;
    approved++;
  }

  res.json({ success: true, approved, fully_verified_earned: fullyVerified, threshold });
});

// ── POST /api/review/run-matcher ──────────────────────────────────────────────
// Trigger the equivalence matcher immediately (admin action)
reviewRouter.post("/run-matcher", async (_req: Request, res: Response) => {
  // Queue the job via pg-boss — import from scraper's db util won't work here,
  // so we fire directly via DB insert into pg-boss queue
  await pool.query(`
    INSERT INTO pgboss.job (name, data, priority)
    VALUES ('maintenance:find-equivalences', '{}', 0)
    ON CONFLICT DO NOTHING
  `);

  res.json({ success: true, message: "Equivalence matcher queued" });
});
