// Deterministic document sectioniser for the archive-ingest path (LinkedIn /
// Obsidian / Notion). Unlike memory-ingest, that path has no LLM section
// classifier, so sectioning must be deterministic: split on markdown ATX
// headings when present, otherwise into fixed-size windows. The parent
// `summary` is a bounded head excerpt — deterministic, no paraphrase. The
// produced sections carry the same { title, body } shape the :Section writer
// expects, so the HAS_SECTION / NEXT graph shape is identical regardless of
// ingest source (Task 636).
const SECTION_MAX_CHARS = 4000;
const SUMMARY_MAX_CHARS = 500;
export function sectioniseDocument(body) {
    const trimmed = (body ?? "").trim();
    if (trimmed.length === 0)
        return { summary: "", sections: [] };
    const summary = trimmed.length > SUMMARY_MAX_CHARS ? trimmed.slice(0, SUMMARY_MAX_CHARS) : trimmed;
    const headingRe = /^#{1,6}\s+(.+)$/gm;
    const matches = [...trimmed.matchAll(headingRe)];
    const sections = [];
    if (matches.length > 0) {
        // Non-empty text before the first heading would otherwise be dropped from
        // every per-section vector — capture it as a leading "Introduction" section
        // so the split is lossless.
        const preamble = trimmed.slice(0, matches[0].index ?? 0).trim();
        if (preamble.length > 0) {
            sections.push({
                title: "Introduction",
                body: preamble.length > SECTION_MAX_CHARS ? preamble.slice(0, SECTION_MAX_CHARS) : preamble,
            });
        }
        for (let i = 0; i < matches.length; i++) {
            const title = matches[i][1].trim();
            const start = (matches[i].index ?? 0) + matches[i][0].length;
            const end = i + 1 < matches.length ? (matches[i + 1].index ?? trimmed.length) : trimmed.length;
            let secBody = trimmed.slice(start, end).trim();
            if (secBody.length > SECTION_MAX_CHARS)
                secBody = secBody.slice(0, SECTION_MAX_CHARS);
            sections.push({ title, body: secBody });
        }
        return { summary, sections };
    }
    // No headings — fixed-size windows.
    for (let i = 0, part = 1; i < trimmed.length; i += SECTION_MAX_CHARS, part++) {
        sections.push({ title: `Part ${part}`, body: trimmed.slice(i, i + SECTION_MAX_CHARS) });
    }
    return { summary, sections };
}
//# sourceMappingURL=document-sectioniser.js.map