#!/usr/bin/env python3
from __future__ import annotations

"""
Legacy FastCDC Implementation

Copied from: /home/voidstr3m33/echo_labs/helix/labs/HELIX_RSA_LABS/ccm_chunking.py

Content-Defined Chunking (CDC) with rolling hash algorithm.
Used in historical CDC stack for robust chunking that's invariant to data shifts.

Default: 64 KiB average chunks (32-128 KiB range)

Historical context:
- Part of original CDC (Compressed-Domain Computing) stack
- Used for chunking before compression
- Enables deduplication and partial updates

Usage:
    from helix_cdc.cdc_legacy.legacy_fastcdc import fastcdc
    
    data = b"..." # Your data
    for start, end in fastcdc(data):
        chunk = data[start:end]
        # Process chunk
"""

from typing import Iterable, Tuple

# ============================================================================
# ORIGINAL IMPLEMENTATION FROM HELIX_RSA_LABS
# ============================================================================

# Rolling mask settings approximating FastCDC
# (Cheap polynomial rolling hash over bytes, not crypto)
def _rol32(x: int, r: int) -> int:
    return ((x << r) & 0xFFFFFFFF) | (x >> (32 - r))

def _roll_hash(prev: int, byte: int) -> int:
    return _rol32(prev, 1) ^ byte

def fastcdc(data: bytes,
            min_size: int = 32*1024,
            avg_size: int = 64*1024,
            max_size: int = 128*1024,
            mask_bits: int = 13) -> Iterable[Tuple[int, int]]:
    """
    FastCDC-style content-defined chunking.
    
    Produces ~avg_size chunks, but boundaries follow content (robust to shifts).
    
    Args:
        data: Input bytes to chunk
        min_size: Minimum chunk size (default: 32KB)
        avg_size: Target average chunk size (default: 64KB)
        max_size: Maximum chunk size (default: 128KB)
        mask_bits: Hash mask bits for boundary detection (default: 13)
    
    Yields:
        (start, end) tuples for each chunk
    """
    n = len(data)
    if n == 0:
        return
    i = 0
    mask = (1 << mask_bits) - 1
    while i < n:
        start = i
        h = 0
        cut = min(i + max(min_size, 1), n)
        # force min size
        while i < cut and i < n:
            h = _roll_hash(h, data[i])
            i += 1
        # prefer average breakpoint where hash & mask == 0
        prefer_end = min(start + avg_size * 2, n)
        while i < prefer_end:
            h = _roll_hash(h, data[i])
            i += 1
            if (h & mask) == 0:
                break
        # hard cap at max_size
        end = min(start + max_size, i)
        yield (start, end)
        i = end
