import { Router, Request, Response } from "express";
import { pool } from "../db/client";
import { semanticSearch } from "../embeddings/client";

export const kbRouter = Router();

// GET /api/kb — Knowledge base browser: FAQ + troubleshooting entries
// ?q=search&category=faq|troubleshooting|known_issue&limit=50&semantic=1
// Falls back to Qdrant semantic search when ILIKE returns 0 results
kbRouter.get("/", async (req: Request, res: Response) => {
  const q        = ((req.query.q as string) || "").trim();
  const category = (req.query.category as string) || "";
  const limit    = Math.min(parseInt((req.query.limit as string) || "60"), 200);
  const forceSemantic = req.query.semantic === "1";

  try {
    const [textEntries, cats] = await Promise.all([
      pool.query(
        `SELECT id, category, subcategory, question, answer,
                applies_to_form_factors, applies_to_speeds, severity, tags
         FROM knowledge_base
         WHERE ($1 = '' OR category = $1)
           AND ($2 = '' OR question    ILIKE '%' || $2 || '%'
                        OR answer      ILIKE '%' || $2 || '%'
                        OR subcategory ILIKE '%' || $2 || '%')
         ORDER BY
           CASE WHEN $2 != '' AND question ILIKE '%' || $2 || '%' THEN 0 ELSE 1 END,
           category, subcategory, id
         LIMIT $3`,
        [category, q, limit]
      ),
      pool.query(
        `SELECT category, COUNT(*)::int AS count
         FROM knowledge_base
         GROUP BY category
         ORDER BY count DESC`
      ),
    ]);

    // If text search found results and semantic not forced, return them
    if (textEntries.rows.length > 0 && !forceSemantic) {
      return res.json({
        success:    true,
        entries:    textEntries.rows,
        categories: cats.rows,
        total:      textEntries.rows.length,
        query:      q,
        search_mode: "text",
      });
    }

    // Semantic fallback — only when query is provided and text search returned nothing
    if (q.length > 2) {
      try {
        const collections: Array<"faq_embeddings" | "troubleshooting_embeddings"> =
          category === "faq" ? ["faq_embeddings"] :
          category === "troubleshooting" ? ["troubleshooting_embeddings"] :
          ["faq_embeddings", "troubleshooting_embeddings"];

        const semanticHits = (
          await Promise.all(
            collections.map(col =>
              semanticSearch(col, q, Math.ceil(limit / collections.length))
                .catch(() => [] as Array<{ id: string; score: number; payload: Record<string, unknown> }>)
            )
          )
        ).flat().sort((a, b) => b.score - a.score);

        // Deduplicate by kb id from payload, then fetch full rows from DB
        const kbIds = [...new Set(
          semanticHits
            .filter(h => h.score >= 0.5 && h.payload.kb_id)
            .slice(0, limit)
            .map(h => h.payload.kb_id as string)
        )];

        if (kbIds.length > 0) {
          const semanticRows = await pool.query(
            `SELECT id, category, subcategory, question, answer,
                    applies_to_form_factors, applies_to_speeds, severity, tags
             FROM knowledge_base
             WHERE id = ANY($1::int[])`,
            [kbIds.map(Number).filter(n => !isNaN(n))]
          );

          // Sort results by semantic score order
          const scoreMap = new Map(semanticHits.map(h => [String(h.payload.kb_id), h.score]));
          const sorted = semanticRows.rows.sort(
            (a, b) => (scoreMap.get(String(b.id)) || 0) - (scoreMap.get(String(a.id)) || 0)
          );

          return res.json({
            success:     true,
            entries:     sorted,
            categories:  cats.rows,
            total:       sorted.length,
            query:       q,
            search_mode: "semantic",
          });
        }
      } catch (_semErr) {
        // Semantic search unavailable — fall through to text results
      }
    }

    // Final fallback: return text results (even if empty)
    return res.json({
      success:    true,
      entries:    textEntries.rows,
      categories: cats.rows,
      total:      textEntries.rows.length,
      query:      q,
      search_mode: "text",
    });
  } catch (err) {
    res.status(500).json({ success: false, error: String(err) });
  }
});
