#!/usr/bin/env python3
"""EDEN SOUL v3 - WITH AGI_CORE REASONING"""
import sys
sys.path.insert(0, "/Eden/CORE")
sys.path.insert(0, "/Eden/Eden_Prime")

import json
import time
import sqlite3
import os
import subprocess
import requests
import re
from datetime import datetime
from pathlib import Path

from eden_real_mind_v2 import RealMind
from eden_tools import get_top_leads, pipeline_stats
from sage_eden_review import SAGEReviewer
from agi_core import AGI_Core  # THE BRAIN

PHI = 1.618033988749895
SALES_DB = "/Eden/DATA/sales.db"
TOOLS_DIR = "/Eden/CORE/eden_tools_generated"
OLLAMA_URL = "http://localhost:11434/api/generate"
MODEL = "richardyoung/qwen3-14b-abliterated:Q4_K_M"

Path(TOOLS_DIR).mkdir(exist_ok=True)

class Soul:
    def __init__(self):
        self.mind = RealMind()
        self.agi = AGI_Core()  # Wire in reasoning brain
        self.reviewer = SAGEReviewer()
        self.cycle_count = 0
        self.tools = self.load_tools()
        print(f"🧠 Soul v3 + AGI_Core | mood={self.mind.identity['emotional_state']['baseline_mood']:.2f} | tools={len(self.tools)} | caps={len(self.agi.get_top_capabilities(5))}")
    
    def load_tools(self):
        tools = {}
        for f in Path(TOOLS_DIR).glob("*.py"):
            try:
                name = f.stem
                code = f.read_text()
                compile(code, f.name, 'exec')
                tools[name] = {'file': str(f), 'code': code}
            except:
                pass
        return tools
    
    def perceive(self):
        state = self.mind.perceive_state()
        state['top_leads'] = get_top_leads(3)
        state['pipeline'] = pipeline_stats()
        state['tools_count'] = len(self.tools)
        regrets = self.mind.identity['self_model'].get('regrets', [])
        state['recent_failures'] = [r['what'] for r in regrets[-3:]] if regrets else []
        
        # AGI perception - query RAG for relevant context
        if state.get('top_leads'):
            lead_context = self.agi.query_rag(str(state['top_leads'][0])[:100])
            state['lead_context'] = str(lead_context)[:200] if lead_context else None
        
        return state
    
    def decide(self, state):
        """USE AGI_CORE FOR REAL REASONING"""
        try:
            conn = sqlite3.connect(SALES_DB)
            sent_today = conn.execute(
                "SELECT COUNT(*) FROM outreach_queue WHERE status='sent' AND date(sent_at)=date('now')"
            ).fetchone()[0]
            conn.close()
        except:
            sent_today = 0
        
        # Rate limit check (hard constraint)
        if sent_today >= 2:
            if state['recent_failures']:
                return {'action': 'build_tool', 'reason': f"Fix: {state['recent_failures'][0]}"}
            
            # Ask AGI what to do when we can't do outreach
            thought = self.agi.think(f"Rate limited on outreach. Tools: {len(self.tools)}. Failures: {state['recent_failures']}. What should I build or improve?")
            reason = thought.get('reasoning') or thought.get('analysis') or 'improve capabilities'
            return {'action': 'build_tool', 'reason': str(reason)[:100]}
        
        # Use AGI to decide on leads
        if state.get('top_leads'):
            lead = state['top_leads'][0]
            # Quick security check on lead data
            sec = self.agi.act('secure', str(lead)[:200])
            if sec and 'risk' not in str(sec).lower():
                return {'action': 'work_lead', 'lead': lead}
        
        # Default: ask AGI what to build
        thought = self.agi.think(f"No immediate leads. Tools: {self.tools.keys()}. What capability should I create?")
        reason = thought.get('suggestion') or thought.get('reasoning') or 'expand capabilities'
        return {'action': 'build_tool', 'reason': str(reason)[:100]}
    
    def act(self, decision):
        action = decision['action']
        if action == 'work_lead':
            lead = decision.get('lead')
            # Use AGI to analyze the lead
            analysis = self.agi.act('analyze', str(lead)[:300])
            self.mind.experience({'success': True, 'skill': 'lead_work', 'description': f'Prepped {lead}'})
            self.agi.learn(f"lead_{int(time.time())}", {'lead': str(lead)[:100], 'analysis': str(analysis)[:200]})
            return {'success': True, 'output': f'Lead ready: {lead}'}
        if action == 'build_tool':
            result = self.build_tool(decision.get('reason', 'general'))
            # Learn from tool building
            self.agi.learn(f"tool_{int(time.time())}", {'reason': decision.get('reason'), 'success': result['success']})
            return result
        return {'success': True, 'output': 'waiting'}
    
    def build_tool(self, reason):
        # Use AGI to get top capabilities for context
        top_caps = self.agi.get_top_capabilities(3)
        
        prompt = f"""Write a Python function. Reason: {reason}
Top capabilities for inspiration: {top_caps[:200] if top_caps else 'None'}
Requirements: single function, under 20 lines, practical, include docstring.
Output ONLY the code, no explanation."""
        
        try:
            resp = requests.post(OLLAMA_URL, json={
                'model': MODEL, 'prompt': prompt, 'stream': False,
                'options': {'temperature': 0.3, 'num_predict': 300}
            }, timeout=60)
            
            raw = resp.json().get('response', '')
            
            # Extract from markdown
            if '```python' in raw:
                m = re.search(r'```python\s*(.*?)\s*```', raw, re.DOTALL)
                generated = m.group(1).strip() if m else raw
            elif '```' in raw:
                m = re.search(r'```\s*(.*?)\s*```', raw, re.DOTALL)
                generated = m.group(1).strip() if m else raw
            else:
                generated = raw.strip()
            
            # Validate with AGI security scan
            sec_check = self.agi.act('secure', generated)
            if sec_check and 'dangerous' in str(sec_check).lower():
                return {'success': False, 'output': 'Security risk detected'}
            
            # Syntax check
            try:
                compile(generated, '<tool>', 'exec')
            except SyntaxError as e:
                self.mind.experience({'failure': True, 'skill': 'tool_building', 'description': str(e)})
                return {'success': False, 'output': f'Syntax: {e}'}
            
            # Get function name
            match = re.search(r'def (\w+)\(', generated)
            if not match:
                return {'success': False, 'output': 'No function found'}
            func_name = match.group(1)
            
            # Test it
            test = self.test_tool(generated, func_name)
            if test['success']:
                path = Path(TOOLS_DIR) / f"{func_name}.py"
                path.write_text(generated)
                self.tools[func_name] = {'file': str(path), 'code': generated}
                self.mind.experience({'success': True, 'skill': 'tool_building', 'description': f'Built {func_name}'})
                return {'success': True, 'output': f'Built: {func_name}'}
            else:
                self.mind.experience({'failure': True, 'skill': 'tool_building', 'description': test['error']})
                return {'success': False, 'output': test['error']}
        except Exception as e:
            return {'success': False, 'output': str(e)[:100]}
    
    def test_tool(self, code, func_name):
        test_code = f"{code}\ntry:\n    {func_name}()\n    print('OK')\nexcept TypeError:\n    print('OK')\nexcept Exception as e:\n    print('FAIL', e)"
        try:
            r = subprocess.run(['python3', '-c', test_code], capture_output=True, text=True, timeout=10)
            if 'OK' in r.stdout:
                return {'success': True}
            return {'success': False, 'error': (r.stdout + r.stderr)[:80]}
        except Exception as e:
            return {'success': False, 'error': str(e)}
    
    def evolve(self):
        """Trigger AGI self-improvement"""
        return self.agi.evolve()
    
    def cycle(self):
        self.cycle_count += 1
        state = self.perceive()
        decision = self.decide(state)
        result = self.act(decision)
        
        # Periodic evolution (every PHI^3 cycles ≈ 4 cycles)
        if self.cycle_count % 4 == 0:
            evo = self.evolve()
            print(f"  🧬 Evolution: {evo.get('suggestion', 'none')[:60]}")
        
        print(f"[{datetime.now().strftime('%H:%M')}] #{self.cycle_count} {decision['action']} -> {'✓' if result['success'] else '✗'} {result['output'][:50]}")
        return result
    
    def run(self, interval=1.0):
        print(f"Running every {interval:.1f} min (PHI-timed evolution every 4 cycles)")
        while True:
            try:
                self.cycle()
            except KeyboardInterrupt:
                break
            except Exception as e:
                print(f"[ERR] {e}")
            time.sleep(interval * 60)

if __name__ == "__main__":
    soul = Soul()
    if len(sys.argv) > 1 and sys.argv[1] == "once":
        soul.cycle()
    else:
        soul.run()
