/**
 * Buffer manipulation utilities for protocol detection
 */

// Import from protocols
import { HttpParser } from '../../protocols/http/index.js';

/**
 * BufferAccumulator class for handling fragmented data
 */
export class BufferAccumulator {
  private chunks: Buffer[] = [];
  private totalLength = 0;
  
  /**
   * Append data to the accumulator
   */
  append(data: Buffer): void {
    this.chunks.push(data);
    this.totalLength += data.length;
  }
  
  /**
   * Get the accumulated buffer
   */
  getBuffer(): Buffer {
    if (this.chunks.length === 0) {
      return Buffer.alloc(0);
    }
    if (this.chunks.length === 1) {
      return this.chunks[0];
    }
    return Buffer.concat(this.chunks, this.totalLength);
  }
  
  /**
   * Get current buffer length
   */
  length(): number {
    return this.totalLength;
  }
  
  /**
   * Clear all accumulated data
   */
  clear(): void {
    this.chunks = [];
    this.totalLength = 0;
  }
  
  /**
   * Check if accumulator has minimum bytes
   */
  hasMinimumBytes(minBytes: number): boolean {
    return this.totalLength >= minBytes;
  }
}

/**
 * Read a big-endian 16-bit integer from buffer
 */
export function readUInt16BE(buffer: Buffer, offset: number): number {
  if (offset + 2 > buffer.length) {
    throw new Error('Buffer too short for UInt16BE read');
  }
  return (buffer[offset] << 8) | buffer[offset + 1];
}

/**
 * Read a big-endian 24-bit integer from buffer
 */
export function readUInt24BE(buffer: Buffer, offset: number): number {
  if (offset + 3 > buffer.length) {
    throw new Error('Buffer too short for UInt24BE read');
  }
  return (buffer[offset] << 16) | (buffer[offset + 1] << 8) | buffer[offset + 2];
}

/**
 * Find a byte sequence in a buffer
 */
export function findSequence(buffer: Buffer, sequence: Buffer, startOffset = 0): number {
  if (sequence.length === 0) {
    return startOffset;
  }
  
  const searchLength = buffer.length - sequence.length + 1;
  for (let i = startOffset; i < searchLength; i++) {
    let found = true;
    for (let j = 0; j < sequence.length; j++) {
      if (buffer[i + j] !== sequence[j]) {
        found = false;
        break;
      }
    }
    if (found) {
      return i;
    }
  }
  return -1;
}

/**
 * Extract a line from buffer (up to CRLF or LF)
 */
export function extractLine(buffer: Buffer, startOffset = 0): { line: string; nextOffset: number } | null {
  // Delegate to protocol parser
  return HttpParser.extractLine(buffer, startOffset);
}

/**
 * Check if buffer starts with a string (case-insensitive)
 */
export function startsWithString(buffer: Buffer, str: string, offset = 0): boolean {
  if (offset + str.length > buffer.length) {
    return false;
  }
  
  const bufferStr = buffer.slice(offset, offset + str.length).toString('utf8');
  return bufferStr.toLowerCase() === str.toLowerCase();
}

/**
 * Safe buffer slice that doesn't throw on out-of-bounds
 */
export function safeSlice(buffer: Buffer, start: number, end?: number): Buffer {
  const safeStart = Math.max(0, Math.min(start, buffer.length));
  const safeEnd = end === undefined 
    ? buffer.length 
    : Math.max(safeStart, Math.min(end, buffer.length));
    
  return buffer.slice(safeStart, safeEnd);
}

/**
 * Check if buffer contains printable ASCII
 */
export function isPrintableAscii(buffer: Buffer, length?: number): boolean {
  // Delegate to protocol parser
  return HttpParser.isPrintableAscii(buffer, length);
}