import { extractHighlights } from "../search/highlights.js";
import { buildCitationGraph } from "./citation-graph.js";
import { detectEntityGaps } from "./entity-extractor.js";
const MAX_HIGHLIGHTS = 12;
const MAX_KEY_FINDING_LEN = 280;
const MAX_TOPICS = 8;
const MAX_CROSS_REFS = 10;
const MIN_PHRASE_LEN = 4;
async function buildResearchBrief(question, sources, subQueries, perSourceCharCap, totalSourcesCharCap, queryType = "general", comparisonEntities = [], synthesisText) {
  const fetched = sources.filter((s) => s.fetched && s.markdown_content.length > 0);
  const searchItems = fetched.map((s) => ({
    title: s.title,
    url: s.url,
    snippet: s.markdown_content.slice(0, 200),
    markdown_content: s.markdown_content,
    relevance_score: s.relevance_score
  }));
  const { highlights } = await extractHighlights(question, searchItems, MAX_HIGHLIGHTS);
  const topics = buildTopics(subQueries, fetched);
  const keyFindings = buildKeyFindings(fetched);
  const crossReferences = detectCrossReferences(fetched);
  const gaps = [
    ...detectGaps(subQueries, fetched),
    ...detectEntityGaps(question, subQueries)
  ];
  const comparison = queryType === "comparison" && comparisonEntities.length >= 2 ? buildComparisonSection(comparisonEntities, fetched) : void 0;
  let citationGraph;
  if (synthesisText && synthesisText.trim().length > 0 && fetched.length > 0) {
    const rawGraph = buildCitationGraph(
      synthesisText,
      fetched.map((s) => ({ url: s.url, title: s.title, markdown: s.markdown_content }))
    );
    const fetchedToFullIndex = fetched.map((s) => sources.indexOf(s));
    citationGraph = rawGraph.map((entry) => ({
      ...entry,
      source_indices: entry.source_indices.map((idx) => fetchedToFullIndex[idx]).filter((idx) => idx >= 0)
    }));
  }
  return {
    topics,
    highlights,
    key_findings: keyFindings,
    per_source_char_cap: perSourceCharCap,
    total_sources_char_cap: totalSourcesCharCap,
    sections: {
      overview: {
        key_findings: keyFindings.slice(0, 5),
        cross_references: crossReferences
      },
      ...comparison ? { comparison } : {},
      gaps
    },
    query_type: queryType,
    ...citationGraph && citationGraph.length > 0 ? { citation_graph: citationGraph } : {}
  };
}
function buildTopics(subQueries, sources) {
  if (subQueries.length > 0) {
    return dedupe(subQueries).slice(0, MAX_TOPICS);
  }
  const labels = sources.map((s) => s.title.split(/[–|:·-]/)[0].trim()).filter((t) => t.length >= 5 && t.length <= 100);
  return dedupe(labels).slice(0, MAX_TOPICS);
}
function buildKeyFindings(sources) {
  const out = [];
  for (const s of [...sources].sort((a, b) => b.relevance_score - a.relevance_score)) {
    const first = firstSubstantiveParagraph(s.markdown_content);
    if (!first) continue;
    const trimmed = first.length > MAX_KEY_FINDING_LEN ? first.slice(0, MAX_KEY_FINDING_LEN - 1).trimEnd() + "\u2026" : first;
    out.push(trimmed);
  }
  return dedupe(out);
}
function detectCrossReferences(sources) {
  if (sources.length < 2) return [];
  const phraseMap = /* @__PURE__ */ new Map();
  for (let idx = 0; idx < sources.length; idx++) {
    const content = sources[idx].markdown_content.toLowerCase();
    const words = content.replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length >= MIN_PHRASE_LEN && !STOP_WORDS.has(w));
    const seenForSource = /* @__PURE__ */ new Set();
    for (let i = 0; i < words.length - 2; i++) {
      const phrase = words.slice(i, i + 3).join(" ");
      if (seenForSource.has(phrase)) continue;
      seenForSource.add(phrase);
      if (!phraseMap.has(phrase)) phraseMap.set(phrase, /* @__PURE__ */ new Set());
      phraseMap.get(phrase).add(idx);
    }
  }
  const candidates = [];
  for (const [phrase, sourceIndices] of phraseMap) {
    if (sourceIndices.size >= 2) {
      candidates.push({
        finding: phrase,
        source_indices: [...sourceIndices].sort(),
        confidence: sourceIndices.size >= 3 ? "high" : "medium"
      });
    }
  }
  candidates.sort((a, b) => b.source_indices.length - a.source_indices.length);
  return deduplicateOverlapping(candidates).slice(0, MAX_CROSS_REFS);
}
function deduplicateOverlapping(refs) {
  const kept = [];
  const usedWords = /* @__PURE__ */ new Set();
  for (const ref of refs) {
    const words = ref.finding.split(" ");
    const overlapCount = words.filter((w) => usedWords.has(w)).length;
    if (overlapCount >= words.length - 1 && kept.length > 0) continue;
    kept.push(ref);
    for (const w of words) usedWords.add(w);
  }
  return kept;
}
function detectGaps(subQueries, sources) {
  if (subQueries.length === 0) return [];
  const gaps = [];
  const contentLower = sources.map((s) => s.markdown_content.toLowerCase()).join(" ");
  for (const query of subQueries) {
    const words = query.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length >= MIN_PHRASE_LEN && !STOP_WORDS.has(w));
    if (words.length === 0) continue;
    const found = words.filter((w) => contentLower.includes(w)).length;
    const coverage = found / words.length;
    if (coverage < 0.5) {
      gaps.push(`Limited coverage for: "${query}"`);
    }
  }
  return gaps;
}
function buildComparisonSection(entities, sources) {
  const comparisonPoints = [];
  const contentLower = sources.map((s) => s.markdown_content.toLowerCase()).join("\n");
  const comparisonTerms = [
    "faster",
    "slower",
    "better",
    "worse",
    "more",
    "less",
    "easier",
    "harder",
    "simpler",
    "complex",
    "lightweight",
    "heavy",
    "performance",
    "scalability",
    "ecosystem",
    "community",
    "support"
  ];
  for (const term of comparisonTerms) {
    if (!contentLower.includes(term)) continue;
    const nearEntity = entities.some((e) => {
      const entityLower = e.toLowerCase();
      const idx = contentLower.indexOf(entityLower);
      if (idx === -1) return false;
      const neighborhood = contentLower.slice(Math.max(0, idx - 200), idx + e.length + 200);
      return neighborhood.includes(term);
    });
    if (nearEntity) {
      comparisonPoints.push(term);
    }
  }
  return { entities, comparison_points: [...new Set(comparisonPoints)] };
}
function firstSubstantiveParagraph(markdown) {
  const paragraphs = markdown.split(/\n\n+/).map((p) => p.trim());
  for (const p of paragraphs) {
    if (p.length < 80) continue;
    if (p.startsWith("#") || p.startsWith("|") || p.startsWith("```")) continue;
    const cleaned = stripMarkdownLinks(p);
    if (cleaned.length < 80) continue;
    return cleaned.replace(/\s+/g, " ");
  }
  return null;
}
function stripMarkdownLinks(text) {
  return text.replace(/!\[[^\]]*\]\([^)]*\)/g, "").replace(/\[!\[[^\]]*\]\([^)]*\)\]\([^)]*\)/g, "").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/\[([^\]]+)\]\[[^\]]*\]/g, "$1").replace(/<a\b[^>]*>([\s\S]*?)<\/a>/gi, "$1").replace(/<https?:\/\/[^>]+>/g, "").replace(/https?:\/\/\S+/g, "").replace(/\s{2,}/g, " ").trim();
}
function dedupe(list) {
  const seen = /* @__PURE__ */ new Set();
  const out = [];
  for (const item of list) {
    const key = item.toLowerCase();
    if (seen.has(key)) continue;
    seen.add(key);
    out.push(item);
  }
  return out;
}
const STOP_WORDS = /* @__PURE__ */ new Set([
  "about",
  "after",
  "also",
  "been",
  "before",
  "being",
  "between",
  "both",
  "could",
  "does",
  "doing",
  "done",
  "each",
  "even",
  "every",
  "from",
  "have",
  "here",
  "into",
  "just",
  "like",
  "made",
  "make",
  "many",
  "more",
  "most",
  "much",
  "must",
  "need",
  "only",
  "other",
  "over",
  "same",
  "should",
  "some",
  "such",
  "than",
  "that",
  "their",
  "them",
  "then",
  "there",
  "these",
  "they",
  "this",
  "those",
  "through",
  "very",
  "want",
  "well",
  "were",
  "what",
  "when",
  "where",
  "which",
  "while",
  "will",
  "with",
  "would",
  "your"
]);
export {
  buildResearchBrief,
  detectCrossReferences,
  stripMarkdownLinks
};
//# sourceMappingURL=brief.js.map