import { Injectable } from '@nestjs/common';

export interface TextChunk {
  content: string;
  index: number;
  startPosition: number;
  endPosition: number;
}

@Injectable()
export class TextChunkerService {
  chunkText(
    text: string,
    chunkSize: number = 1000,
    overlap: number = 200,
  ): TextChunk[] {
    if (!text || text.trim().length === 0) {
      return [];
    }

    const cleanText = text.trim();
    const chunkSizeInChars = chunkSize * 4; // 1 token ≈ 4 chars
    const overlapInChars = overlap * 4;

    // If text length <= chunk size, return entire text as one chunk
    if (cleanText.length <= chunkSizeInChars) {
      return [
        {
          content: cleanText,
          index: 0,
          startPosition: 0,
          endPosition: cleanText.length,
        },
      ];
    }

    const chunks: TextChunk[] = [];
    let start = 0;
    let index = 0;

    while (start < cleanText.length) {
      let end = Math.min(start + chunkSizeInChars, cleanText.length);

      // Split by sentence boundaries
      if (end < cleanText.length) {
        const sentenceEnd = this.findSentenceEnd(
          cleanText,
          end,
          start + chunkSizeInChars * 0.8,
        );
        if (sentenceEnd > start) {
          end = sentenceEnd;
        }
      }

      const content = cleanText.slice(start, end).trim();
      if (content.length > 0) {
        chunks.push({
          content,
          index,
          startPosition: start,
          endPosition: end,
        });
        index++;
      }

      // Fix infinite loop: if we reached the end, stop here.
      if (end >= cleanText.length) {
        break;
      }

      // Calculate start position of next chunk
      const newStart = end - overlapInChars;
      // Protect against infinite loop if overlap is too large or chunk too small
      if (newStart <= start) {
        start = end; // Force advance if overlap would cause stagnation
      } else {
        start = newStart;
      }
    }

    return chunks;
  }

  private findSentenceEnd(
    text: string,
    preferredEnd: number,
    minEnd: number,
  ): number {
    const sentenceEnders = ['.', '!', '?', '。', '！', '？'];

    for (let i = preferredEnd; i >= minEnd; i--) {
      if (sentenceEnders.includes(text[i])) {
        return i + 1;
      }
    }

    for (let i = preferredEnd; i >= minEnd; i--) {
      if (text[i] === ' ' || text[i] === '\n') {
        return i;
      }
    }

    return preferredEnd;
  }
}
