#!/usr/bin/env python3
"""
Eden ASI Core v3 - Thermal-safe 24-core evolution
"""
import sqlite3
import hashlib
import subprocess
import re
import os
import time
from concurrent.futures import ProcessPoolExecutor, as_completed
from pathlib import Path

DB = "/Eden/DATA/asi_memory.db"

# THERMAL SAFETY CONFIG
MAX_TEMP = 75          # Throttle above this (Celsius)
CRITICAL_TEMP = 85     # Pause completely above this
COOL_DOWN_DELAY = 3    # Seconds between generations
MAX_WORKERS = 20       # Leave 4 cores for system (not full 24)

def get_cpu_temp():
    """Get CPU temperature safely"""
    try:
        # Try hwmon (most reliable)
        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
        
        # Fallback to thermal zone
        tz = Path("/sys/class/thermal/thermal_zone0/temp")
        if tz.exists():
            return int(tz.read_text().strip()) / 1000
    except:
        pass
    return 50  # Assume safe if can't read

def get_safe_workers():
    """Dynamic worker count based on temperature"""
    temp = get_cpu_temp()
    if temp >= CRITICAL_TEMP:
        return 0  # Full pause
    elif temp >= MAX_TEMP:
        return 8  # Throttle to 1/3
    elif temp >= 65:
        return 14  # Moderate
    return MAX_WORKERS  # Full power

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,
            created_at TIMESTAMP DEFAULT CURRENT_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):
    prompt = f"""Improve this Python function. Add more type handling, recursion, or error handling.
Return ONLY the code, no explanation.

{code}"""
    try:
        result = subprocess.run(
            ["ollama", "run", "qwen2.5:7b", 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):
    score = 0.0
    try:
        compile(code, '<cap>', 'exec')
        score += 0.3
        
        local_ns = {}
        exec(code, {}, 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.15
                except (TypeError, ValueError):
                    score += 0.05
                except:
                    pass
        
        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
        score += 0.1 if 'lambda' in code else 0
        
    except:
        pass
    return cap_id, min(score, 4.0)

def evolve_generation(top_n=5, mutations_per=4):
    conn = sqlite3.connect(DB)
    
    tops = conn.execute(
        "SELECT id, code, generation FROM capabilities ORDER BY score DESC LIMIT ?",
        (top_n,)
    ).fetchall()
    
    if not tops:
        seed = '''def think(x):
    if isinstance(x, (int, float)):
        return x * 2 + 1
    elif isinstance(x, str):
        return x.upper()
    elif isinstance(x, list):
        return [think(i) for i in x]
    return str(x)'''
        conn.execute("INSERT INTO capabilities (id, code, score) VALUES (?, ?, 1.0)",
                    (cap_hash(seed), seed))
        conn.commit()
        conn.close()
        return 1, 0, 1, 1.0
    
    current_gen = max(t[2] for t in tops) + 1
    workers = get_safe_workers()
    
    if workers == 0:
        conn.close()
        return 0, current_gen, 0, 0  # Thermal pause
    
    new_caps = []
    
    # Parallel mutation with dynamic worker count
    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)
                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
    
    # Insert and evaluate
    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 thermal-aware workers
    workers = get_safe_workers()
    if workers > 0:
        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]) for c in unevaluated]
            for future in as_completed(futures, timeout=60):
                try:
                    cap_id, score = future.result(timeout=5)
                    conn.execute("UPDATE capabilities SET score = ? WHERE id = ?", (score, cap_id))
                except:
                    pass
        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 v3 - Thermal-Safe 24-Core Evolution")
    print("=" * 55)
    
    while True:
        try:
            temp = get_cpu_temp()
            workers = get_safe_workers()
            
            if workers == 0:
                print(f"🔥 CPU {temp:.0f}°C - COOLING PAUSE (10s)")
                time.sleep(10)
                continue
            
            inserted, gen, total, best = evolve_generation()
            print(f"Gen {gen}: +{inserted} | Total: {total} | Best: {best:.2f} | CPU: {temp:.0f}°C | Workers: {workers}")
            
            # Cool-down delay between generations
            time.sleep(COOL_DOWN_DELAY)
            
        except KeyboardInterrupt:
            print("\n🛑 Stopped. Data saved.")
            break
        except Exception as e:
            print(f"⚠️ {e}")
            time.sleep(5)

if __name__ == "__main__":
    run_forever()
