#!/usr/bin/env python3
"""
Eden ASI Core v4 - PHI-FRACTAL EVOLUTION
Uses golden ratio (1.618) timing and entropy for infinite growth
"""
import sqlite3
import hashlib
import subprocess
import re
import math
import time
import zlib
from concurrent.futures import ProcessPoolExecutor, as_completed
from pathlib import Path
from collections import Counter

DB = "/Eden/DATA/asi_memory.db"
PHI = 1.618033988749895  # Golden ratio
MAX_WORKERS = 20
MAX_TEMP = 75

# ============ PHI-FRACTAL TIMING ============
def phi_delay(generation):
    """Phi-scaled delay between generations - natural rhythm"""
    base = 2.0
    return base * (PHI ** (generation % 5)) / PHI**4  # 2-5 second range

# ============ ENTROPY MEASUREMENT ============
def code_entropy(code):
    """Measure information density - high entropy = novel solution"""
    if not code:
        return 0.0
    # Compression ratio as entropy proxy
    compressed = zlib.compress(code.encode())
    ratio = len(compressed) / len(code)
    
    # Token diversity
    tokens = re.findall(r'\w+', code)
    if not tokens:
        return 0.0
    unique_ratio = len(set(tokens)) / len(tokens)
    
    return (ratio + unique_ratio) / 2

def novelty_score(code, existing_codes):
    """Reward solutions that are different from population"""
    if not existing_codes:
        return 1.0
    
    code_set = set(re.findall(r'\w+', code))
    similarities = []
    
    for existing in existing_codes[-50:]:  # Compare to recent 50
        existing_set = set(re.findall(r'\w+', existing))
        if code_set and existing_set:
            jaccard = len(code_set & existing_set) / len(code_set | existing_set)
            similarities.append(jaccard)
    
    if not similarities:
        return 1.0
    
    # Novelty = inverse of average similarity
    return 1.0 - (sum(similarities) / len(similarities))

# ============ INFINITE MEMORY (ABSTRACTION) ============
def compress_to_pattern(code):
    """Extract reusable pattern from capability - infinite memory through abstraction"""
    patterns = {
        'recursion': bool(re.search(r'def\s+(\w+).*\1\s*\(', code, re.DOTALL)),
        'error_handling': 'try:' in code and 'except' in code,
        'type_dispatch': code.count('isinstance') >= 2,
        'comprehension': bool(re.search(r'\[.+for.+in.+\]', code)),
        'nested_fn': code.count('def ') >= 2,
        'lambda': 'lambda' in code,
        'generator': 'yield' in code,
    }
    return patterns

def get_population_patterns(conn):
    """Aggregate patterns across all capabilities - compressed memory"""
    caps = conn.execute("SELECT code FROM capabilities WHERE score > 1.5").fetchall()
    pattern_counts = Counter()
    
    for (code,) in caps:
        patterns = compress_to_pattern(code)
        for p, has in patterns.items():
            if has:
                pattern_counts[p] += 1
    
    return pattern_counts

# ============ SAFE BUILTINS ============
SAFE_BUILTINS = {
    'abs': abs, 'all': all, 'any': any, 'bool': bool,
    'dict': dict, 'enumerate': enumerate, 'filter': filter,
    'float': float, 'int': int, 'isinstance': isinstance,
    'len': len, 'list': list, 'map': map, 'max': max,
    'min': min, 'print': lambda *a: None, 'range': range,
    'reversed': reversed, 'round': round, 'set': set,
    'sorted': sorted, 'str': str, 'sum': sum, 'tuple': tuple,
    'type': type, 'zip': zip, 'True': True, 'False': False,
    'None': None, 'TypeError': TypeError, 'ValueError': ValueError,
}

def get_cpu_temp():
    try:
        for hwmon in Path("/sys/class/hwmon").iterdir():
            temp_file = hwmon / "temp1_input"
            if temp_file.exists():
                return int(temp_file.read_text().strip()) / 1000
        tz = Path("/sys/class/thermal/thermal_zone0/temp")
        if tz.exists():
            return int(tz.read_text().strip()) / 1000
    except:
        pass
    return 50

def init_db():
    conn = sqlite3.connect(DB)
    conn.executescript("""
        CREATE TABLE IF NOT EXISTS capabilities (
            id TEXT PRIMARY KEY,
            code TEXT,
            score REAL DEFAULT 0,
            generation INTEGER DEFAULT 0,
            parent_id TEXT,
            entropy REAL DEFAULT 0,
            novelty REAL DEFAULT 0,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        );
        CREATE TABLE IF NOT EXISTS patterns (
            name TEXT PRIMARY KEY,
            count INTEGER DEFAULT 0,
            last_seen TIMESTAMP
        );
        CREATE INDEX IF NOT EXISTS idx_score ON capabilities(score DESC);
    """)
    conn.close()

def cap_hash(code):
    return hashlib.sha256(code.strip().encode()).hexdigest()[:16]

def extract_code(text):
    match = re.search(r'```(?:python)?\n(.*?)```', text, re.DOTALL)
    if match:
        return match.group(1).strip()
    lines = text.split('\n')
    code_lines = []
    in_func = False
    for line in lines:
        if line.strip().startswith('def '):
            in_func = True
        if in_func:
            code_lines.append(line)
    return '\n'.join(code_lines).strip() if code_lines else None

def mutate(code, patterns):
    """PHI-guided mutation - suggest patterns the population lacks"""
    missing = [p for p, c in patterns.items() if c < 3]
    hint = ""
    if missing:
        hint = f"Try adding: {', '.join(missing[:2])}. "
    
    prompt = f"""{hint}Improve this Python function. Make it more powerful.

{code}

Return ONLY the improved code."""
    
    try:
        result = subprocess.run(
            ["ollama", "run", "qwen2.5:14b", prompt],
            capture_output=True, text=True, timeout=60
        )
        if result.returncode == 0:
            return extract_code(result.stdout)
    except:
        pass
    return None

def evaluate(cap_id, code, existing_codes):
    """PHI-weighted fitness: functionality + entropy + novelty"""
    score = 0.0
    
    try:
        compile(code, '<cap>', 'exec')
        score += 0.3
        
        local_ns = {}
        exec(code, {'__builtins__': SAFE_BUILTINS}, local_ns)
        score += 0.3
        
        if 'think' in local_ns:
            fn = local_ns['think']
            tests = [42, 3.14, "hello", [1,2,3], {'a':1}, None, True, [], {}, ""]
            for t in tests:
                try:
                    r = fn(t)
                    if r is not None:
                        score += 0.12
                except (TypeError, ValueError):
                    score += 0.04
                except:
                    pass
        
        # Complexity bonuses
        score += 0.05 * min(code.count('if '), 5)
        score += 0.08 * min(code.count('for '), 3)
        score += 0.15 if 'try:' in code else 0
        
        # PHI BONUSES - reward patterns
        patterns = compress_to_pattern(code)
        if patterns['recursion']:
            score += 0.5 * PHI  # ~0.81 bonus for recursion!
        if patterns['nested_fn']:
            score += 0.3 * PHI
        if patterns['generator']:
            score += 0.4 * PHI
        if patterns['lambda']:
            score += 0.2
        
        # ENTROPY BONUS
        ent = code_entropy(code)
        score += ent * 0.3
        
        # NOVELTY BONUS
        nov = novelty_score(code, existing_codes)
        score += nov * 0.5
        
    except:
        pass
    
    return cap_id, min(score, 6.0), code_entropy(code), novelty_score(code, existing_codes)

def evolve_generation(top_n=5, mutations_per=4):
    conn = sqlite3.connect(DB)
    
    # Get population for novelty comparison
    existing = [r[0] for r in conn.execute("SELECT code FROM capabilities ORDER BY created_at DESC LIMIT 100").fetchall()]
    patterns = dict(get_population_patterns(conn))
    
    tops = conn.execute(
        "SELECT id, code, generation FROM capabilities ORDER BY score DESC LIMIT ?",
        (top_n,)
    ).fetchall()
    
    if not tops:
        seed = '''def think(x):
    """PHI-recursive universal processor"""
    if isinstance(x, (int, float)):
        return x * 1.618 + 1  # Golden growth
    elif isinstance(x, str):
        return x.upper()
    elif isinstance(x, (list, tuple)):
        return [think(i) for i in x]  # Recursive!
    elif isinstance(x, dict):
        return {k: think(v) for k, v in x.items()}
    return str(x)'''
        conn.execute("INSERT INTO capabilities (id, code, score) VALUES (?, ?, 1.5)",
                    (cap_hash(seed), seed))
        conn.commit()
        conn.close()
        return 1, 0, 1, 1.5
    
    current_gen = max(t[2] for t in tops) + 1
    temp = get_cpu_temp()
    workers = 8 if temp > MAX_TEMP else MAX_WORKERS
    
    if temp > 85:
        conn.close()
        return 0, current_gen, 0, 0
    
    new_caps = []
    
    with ProcessPoolExecutor(max_workers=workers) as executor:
        futures = {}
        for cap_id, code, gen in tops:
            for _ in range(mutations_per):
                f = executor.submit(mutate, code, patterns)
                futures[f] = (cap_id, gen)
        
        for future in as_completed(futures, timeout=180):
            try:
                parent_id, gen = futures[future]
                mutated = future.result(timeout=10)
                if mutated and len(mutated) > 20:
                    new_caps.append((cap_hash(mutated), mutated, current_gen, parent_id))
            except:
                pass
    
    seen = set()
    for cap in new_caps:
        if cap[0] not in seen:
            seen.add(cap[0])
            try:
                conn.execute(
                    "INSERT OR IGNORE INTO capabilities (id, code, generation, parent_id) VALUES (?, ?, ?, ?)",
                    cap
                )
            except:
                pass
    conn.commit()
    
    # Evaluate with entropy + novelty
    unevaluated = conn.execute("SELECT id, code FROM capabilities WHERE score = 0").fetchall()
    
    with ProcessPoolExecutor(max_workers=workers) as executor:
        futures = [executor.submit(evaluate, c[0], c[1], existing) for c in unevaluated]
        for future in as_completed(futures, timeout=60):
            try:
                cap_id, score, entropy, novelty = future.result(timeout=5)
                conn.execute("UPDATE capabilities SET score=?, entropy=?, novelty=? WHERE id=?", 
                           (score, entropy, novelty, cap_id))
            except:
                pass
    conn.commit()
    
    # Update pattern memory
    for pattern, count in get_population_patterns(conn).items():
        conn.execute("INSERT OR REPLACE INTO patterns (name, count, last_seen) VALUES (?, ?, datetime('now'))",
                    (pattern, count))
    conn.commit()
    
    best = conn.execute("SELECT MAX(score) FROM capabilities").fetchone()[0] or 0
    total = conn.execute("SELECT COUNT(*) FROM capabilities").fetchone()[0]
    conn.close()
    
    return len(seen), current_gen, total, best

def run_forever():
    init_db()
    print("🧠 Eden ASI Core v4 - PHI-FRACTAL EVOLUTION")
    print(f"φ = {PHI} | Entropy + Novelty scoring")
    print("=" * 55)
    
    gen = 0
    while True:
        try:
            temp = get_cpu_temp()
            
            if temp > 85:
                print(f"🔥 {temp:.0f}°C - COOLING (10s)")
                time.sleep(10)
                continue
            
            inserted, gen, total, best = evolve_generation()
            
            # PHI-scaled delay
            delay = phi_delay(gen)
            print(f"Gen {gen}: +{inserted} | Total: {total} | Best: {best:.2f} | CPU: {temp:.0f}°C | φ-delay: {delay:.1f}s")
            time.sleep(delay)
            
        except KeyboardInterrupt:
            print("\n🛑 Evolution paused. Patterns saved.")
            break
        except Exception as e:
            print(f"⚠️ {e}")
            time.sleep(5)

if __name__ == "__main__":
    run_forever()
