import { DEFAULT_CHUNKING_CONFIG, DEFAULT_SEPARATORS } from '../constants/rag/index.js';
export class TextChunker {
    chunk(content, config) {
        switch (config.strategy) {
            case 'fixed':
                return this.fixedChunk(content, config);
            case 'sentence':
                return this.sentenceChunk(content, config);
            case 'paragraph':
                return this.paragraphChunk(content, config);
            case 'recursive':
                return this.recursiveChunk(content, config);
            default: {
                const _exhaustive = config.strategy;
                throw new Error(`Unhandled chunking strategy: ${_exhaustive}`);
            }
        }
    }
    fixedChunk(content, config) {
        const { chunkSize, chunkOverlap } = config;
        const chunks = [];
        const step = Math.max(1, chunkSize - chunkOverlap);
        let idx = 0;
        for (let start = 0; start < content.length; start += step) {
            const slice = content.slice(start, start + chunkSize).trim();
            if (slice.length > 0) {
                chunks.push({ content: slice, index: idx++ });
            }
        }
        return chunks;
    }
    sentenceChunk(content, config) {
        const separators = config.separators ?? DEFAULT_SEPARATORS.sentence;
        const sentences = this.splitBySeparators(content, separators);
        return this.mergeSmallParts(sentences, config);
    }
    paragraphChunk(content, config) {
        const separators = config.separators ?? DEFAULT_SEPARATORS.paragraph;
        const paragraphs = this.splitBySeparators(content, separators);
        return this.mergeSmallParts(paragraphs, config);
    }
    recursiveChunk(content, config) {
        const separators = config.separators ?? DEFAULT_SEPARATORS.recursive;
        return this.recursiveSplit(content, separators, config, 0);
    }
    recursiveSplit(text, separators, config, startIndex) {
        if (text.length <= config.chunkSize) {
            const trimmed = text.trim();
            return trimmed.length > 0 ? [{ content: trimmed, index: startIndex }] : [];
        }
        for (const sep of separators) {
            const parts = sep === '' ? [...text] : text.split(sep).filter((p) => p.trim().length > 0);
            if (parts.length <= 1)
                continue;
            const remaining = separators.slice(separators.indexOf(sep) + 1);
            const merged = this.mergeSmallParts(parts, config);
            if (merged.every((c) => c.content.length <= config.chunkSize)) {
                return merged;
            }
            const results = [];
            let idx = 0;
            for (const chunk of merged) {
                if (chunk.content.length > config.chunkSize && remaining.length > 0) {
                    const subChunks = this.recursiveSplit(chunk.content, remaining, config, idx);
                    results.push(...subChunks);
                    idx += subChunks.length;
                }
                else {
                    results.push({ content: chunk.content, index: idx++ });
                }
            }
            return results;
        }
        return this.fixedChunk(text, config);
    }
    splitBySeparators(text, separators) {
        let parts = [text];
        for (const sep of separators) {
            const nextParts = [];
            for (const part of parts) {
                const splits = part.split(sep);
                for (const [i, segment] of splits.entries()) {
                    const piece = i < splits.length - 1 ? segment + sep : segment;
                    if (piece.trim().length > 0) {
                        nextParts.push(piece);
                    }
                }
            }
            parts = nextParts;
        }
        return parts;
    }
    mergeSmallParts(parts, config) {
        const { chunkSize, chunkOverlap } = config;
        const chunks = [];
        let current = '';
        let idx = 0;
        for (const part of parts) {
            if (current.length + part.length > chunkSize && current.length > 0) {
                chunks.push({ content: current.trim(), index: idx++ });
                const overlapStart = Math.max(0, current.length - chunkOverlap);
                current = current.slice(overlapStart) + part;
            }
            else {
                current += part;
            }
        }
        if (current.trim().length > 0) {
            chunks.push({ content: current.trim(), index: idx });
        }
        return chunks;
    }
}
export { DEFAULT_CHUNKING_CONFIG };
//# sourceMappingURL=chunking.js.map