"""
Rebuild Beehive Index from Standalone Package Files

Creates a fresh beehive_index.json from:
- cubesquare/*.py - Package source code
- examples/*.py - Example scripts
- docs/*.md - Documentation

NO PYTHON FOR-LOOPS in hot path.
Index building is setup (bounded), not hot path.
"""
import json
import hashlib
import time
import re
from pathlib import Path
from typing import Dict, List, Any

from ._core import morton_encode, PRIME_131


# Paths
PACKAGE_ROOT = Path(__file__).parent.parent
DATA_DIR = Path(__file__).parent / "data" / "beehive"
INDEX_PATH = DATA_DIR / "beehive_index.json"


def compute_file_hash(content: str) -> int:
    """Hash file content to 64-bit value. O(1) operation."""
    return int(hashlib.sha256(content.encode()).hexdigest()[:16], 16)


def extract_topics(file_path: str, content: str) -> List[str]:
    """Extract topics from file path and content. Setup path, not hot path."""
    topics = []

    # Path components
    parts = re.split(r'[/\\._\-\s:]+', file_path.lower())
    stopwords = {'py', 'md', 'json', 'txt', 'src', 'test', 'tests', 'lib', 'init'}
    topics.extend([p for p in parts if len(p) > 2 and p not in stopwords])

    # Docstring (first 3 lines)
    lines = content.split('\n')[:20]
    for line in lines:
        if '"""' in line or "'''" in line:
            doc_parts = re.split(r'[^a-zA-Z0-9]+', line)
            topics.extend([p.lower() for p in doc_parts if len(p) > 3])
            break

    # Class and function names
    class_pattern = r'class\s+([A-Z][a-zA-Z0-9]+)'
    func_pattern = r'def\s+([a-z_][a-zA-Z0-9_]+)'

    for match in re.finditer(class_pattern, content):
        topics.append(match.group(1).lower())
    for match in re.finditer(func_pattern, content[:5000]):  # Bounded
        name = match.group(1)
        if not name.startswith('_'):
            topics.append(name)

    # Deduplicate
    return list(dict.fromkeys(topics))[:20]


def generate_summary(content: str, k_level: int) -> str:
    """Generate summary at compression level. k0=full, k4=38%, k8=15%."""
    lines = content.split('\n')

    # Extract docstring if present
    doc_lines = []
    in_doc = False
    for line in lines[:50]:  # Bounded
        if '"""' in line or "'''" in line:
            if in_doc:
                doc_lines.append(line.split('"""')[0].split("'''")[0])
                break
            in_doc = True
            doc_lines.append(line.split('"""')[-1].split("'''")[-1])
        elif in_doc:
            doc_lines.append(line)

    doc = ' '.join(doc_lines).strip()

    if k_level == 0:
        return doc[:500] if doc else f"Source file with {len(lines)} lines"
    elif k_level == 4:
        return doc[:200] if doc else f"Source: {len(lines)} lines"
    else:  # k8
        return doc[:80] if doc else f"{len(lines)}L"


def path_to_hex_id(file_path: str) -> str:
    """Convert file path to 8-char hex identity. O(1) operation."""
    file_hash = compute_file_hash(file_path.lower())

    # Derive coordinates (constrained to 48x48x48)
    x = (file_hash >> 0) & 0x3F
    y = (file_hash >> 6) & 0x3F
    z = (file_hash >> 12) & 0x3F
    x, y, z = min(x, 47), min(y, 47), min(z, 47)

    # Compute morton code via C backend
    morton = morton_encode(x, y, z)

    # Compute basin (0-130)
    basin = file_hash % PRIME_131

    # Compute layer
    layer = min(basin * 9 // PRIME_131 + 1, 9)

    # I-state from diagonal
    diagonal = x + y + z
    k11_level = (diagonal % 23) - 11
    i_state = 1 if k11_level >= 0 else 0

    # Pack into 32-bit hex
    packed = (morton & 0xFFFFF) | ((basin & 0xFF) << 20) | ((layer & 0x7) << 28) | ((i_state & 0x1) << 31)
    return f"{packed:08X}"


def rebuild_index() -> Dict[str, Any]:
    """
    Rebuild beehive index from standalone package files.

    Returns:
        Dict with rebuild statistics
    """
    start_time = time.time()

    # Find all source files
    patterns = [
        ('cubesquare', '**/*.py'),
        ('examples', '**/*.py'),
        ('docs', '**/*.md'),
    ]

    files = []
    for subdir, pattern in patterns:
        search_dir = PACKAGE_ROOT / subdir
        if search_dir.exists():
            files.extend(search_dir.glob(pattern))

    # Build tokens
    tokens = {}
    basin_counts = {}

    for file_path in files:
        try:
            rel_path = str(file_path.relative_to(PACKAGE_ROOT))
            content = file_path.read_text(encoding='utf-8', errors='ignore')

            content_hash = compute_file_hash(content)
            hex_id = path_to_hex_id(rel_path)

            # Decode hex to get basin/layer
            packed = int(hex_id, 16)
            basin = (packed >> 20) & 0xFF
            layer = (packed >> 28) & 0x7
            if layer == 0:
                layer = 1

            topics = extract_topics(rel_path, content)

            tokens[hex_id] = {
                'file_path': rel_path,
                'content_hash': content_hash,
                'topics': topics,
                'basin': basin,
                'layer': layer,
                'summaries': {
                    'k0': generate_summary(content, 0),
                    'k4': generate_summary(content, 4),
                    'k8': generate_summary(content, 8),
                },
                'api_refs': [],  # Could extract imports
            }

            basin_counts[basin] = basin_counts.get(basin, 0) + 1

        except Exception as e:
            print(f"Warning: Failed to process {file_path}: {e}")

    # Save index
    DATA_DIR.mkdir(parents=True, exist_ok=True)

    index_data = {
        'version': '1.0.0',
        'created_at': time.strftime('%Y-%m-%dT%H:%M:%S'),
        'saved_at': time.strftime('%Y-%m-%dT%H:%M:%S'),
        'source': 'standalone_package',
        'files_indexed': len(tokens),
        'basins_populated': len(basin_counts),
        'tokens': tokens,
    }

    INDEX_PATH.write_text(json.dumps(index_data, indent=2), encoding='utf-8')

    elapsed_ms = int((time.time() - start_time) * 1000)

    return {
        'status': 'rebuilt',
        'files_indexed': len(tokens),
        'basins_populated': len(basin_counts),
        'index_path': str(INDEX_PATH),
        'index_size_kb': INDEX_PATH.stat().st_size // 1024,
        'elapsed_ms': elapsed_ms,
    }


def main():
    """CLI entry point for rebuilding index."""
    print("Rebuilding beehive index from standalone package files...")
    result = rebuild_index()
    print(f"Done: {result['files_indexed']} files indexed")
    print(f"Basins populated: {result['basins_populated']}")
    print(f"Index size: {result['index_size_kb']} KB")
    print(f"Elapsed: {result['elapsed_ms']} ms")
    print(f"Saved to: {result['index_path']}")


if __name__ == '__main__':
    main()
