import { cosine, embedLocal } from "./embedLocal";
import {
  knowledgeStoresForStep,
  loadStore,
  verticalStoresForStep,
  type ChunkHit,
} from "./stores";
import type { ProcessStep } from "../mortgage/gates";

function knowledgeBoost(sourcePath: string): number {
  const p = sourcePath.replace(/\\/g, "/").toLowerCase();
  if (p.includes("communication.md")) return 0.14;
  if (p.includes("objection.md")) return 0.05;
  if (p.includes("faq.md")) return 0.03;
  if (p.includes("disposition.md")) return 0.01;
  if (p.includes(".html")) return -0.25;
  return 0;
}

function searchStores(
  rels: string[],
  query: string,
  k: number,
  lane: ChunkHit["lane"],
  boost: (source: string) => number
): ChunkHit[] {
  const q = embedLocal(query);
  const hits: ChunkHit[] = [];
  for (const rel of rels) {
    try {
      const store = loadStore(rel);
      for (const item of store.items || []) {
        if (!item.vector || !item.text) continue;
        hits.push({
          id: item.id,
          text: item.text.slice(0, lane === "knowledge" ? 1400 : 700),
          title: item.title || "",
          source_path: item.source_path,
          score: cosine(q, item.vector) + boost(item.source_path),
          lane,
        });
      }
    } catch {
      /* missing store */
    }
  }
  hits.sort((a, b) => b.score - a.score);
  const seen = new Set<string>();
  const out: ChunkHit[] = [];
  for (const h of hits) {
    if (seen.has(h.id)) continue;
    seen.add(h.id);
    out.push(h);
    if (out.length >= k) break;
  }
  return out;
}

/** Talk tracks from data/knowledge (ingested knowledge_base). */
export function retrieveKnowledge(query: string, step: ProcessStep, k = 6): ChunkHit[] {
  return searchStores(knowledgeStoresForStep(step), query, k, "knowledge", knowledgeBoost);
}

/** Dataset / process fields from data/verticals — state management only. */
export function retrieveVertical(query: string, step: ProcessStep, k = 4): ChunkHit[] {
  return searchStores(verticalStoresForStep(step), query, k, "vertical", () => 0);
}

/** Dual-lane RAG: communication vs data, never mixed into one ranked list. */
export function retrieveRag(userMessage: string, step: ProcessStep, missing: string[]) {
  const talkQuery = [
    userMessage,
    "natural phone conversation mortgage protection",
    "one question at a time",
    missing.length ? `still need: ${missing.join(", ")}` : "",
  ]
    .filter(Boolean)
    .join("\n");
  const dataQuery = [
    "ApplicantProfile mortgage dataset fields",
    missing.join(" "),
    userMessage,
  ].join("\n");
  return {
    knowledge: retrieveKnowledge(talkQuery, step, 6),
    verticals: retrieveVertical(dataQuery, step, 4),
  };
}

/** Compat: knowledge lane only so HTML process pages do not win the chat. */
export function retrieve(query: string, step: ProcessStep, k = 8): ChunkHit[] {
  return retrieveKnowledge(query, step, k);
}
