#!/usr/bin/env python3
"""
Grok Crypto Trading Bot - WebSocket Server v1.0
Real-time streaming of prices, trades, and Grok insights
Integrates with NEOG Matrix Portal

Port: 9003
Author: NEOG System
Created: 2025-01-25
"""

from flask import Flask, jsonify, request
from flask_socketio import SocketIO, emit
from flask_cors import CORS
import sqlite3
import json
import os
import sys
import threading
import time
from datetime import datetime, timedelta
from typing import Dict, List

# Import bot components (assumes crypto-grok-bot.py is in same directory)
sys.path.insert(0, '/Users/neog')
try:
    from pycoingecko import CoinGeckoAPI
    import requests
except ImportError:
    print("❌ Missing dependencies. Install: pip3 install pycoingecko requests flask flask-socketio flask-cors")
    sys.exit(1)

# ========== CONFIGURATION ==========

app = Flask(__name__)
app.config['SECRET_KEY'] = 'crypto-grok-secret-2025'
CORS(app, resources={r"/*": {"origins": ["http://localhost:*", "http://100.75.88.8:*"]}})
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading')

DB_PATH = '/Users/neog/crypto_trades.db'
COINS = ['grok', 'bittensor', 'fetch-ai']
CHECK_INTERVAL = int(os.getenv('CRYPTO_CHECK_INTERVAL', '60'))

cg = CoinGeckoAPI()

# Historical data (last 60 samples = 1 hour at 60s interval)
history = {
    'prices': [],      # [{timestamp, grok, bittensor, fetch-ai}]
    'portfolio': [],   # [{timestamp, total_value, cash, holdings}]
    'trades': []       # Recent trades (last 20)
}
MAX_HISTORY = 60

# Current state
current_state = {
    'prices': {},
    'portfolio': {'cash': 140000, 'holdings': {}},
    'last_grok_insights': [],
    'bot_running': False,
    'last_update': None
}

# ========== DATABASE HELPERS ==========

def get_db():
    """Get database connection"""
    return sqlite3.connect(DB_PATH, check_same_thread=False)

def fetch_recent_trades(limit=20) -> List[Dict]:
    """Fetch recent trades from database"""
    try:
        conn = get_db()
        cursor = conn.cursor()
        cursor.execute('''
            SELECT timestamp, coin, action, price_usd, amount_brl, units, grok_reason, portfolio_value_brl, runway_months
            FROM trades
            ORDER BY id DESC
            LIMIT ?
        ''', (limit,))

        trades = []
        for row in cursor.fetchall():
            trades.append({
                'timestamp': row[0],
                'coin': row[1],
                'action': row[2],
                'price_usd': row[3],
                'amount_brl': row[4],
                'units': row[5],
                'grok_reason': row[6],
                'portfolio_value_brl': row[7],
                'runway_months': row[8]
            })

        conn.close()
        return trades
    except Exception as e:
        print(f"❌ Error fetching trades: {e}")
        return []

def fetch_portfolio_snapshot() -> Dict:
    """Fetch latest portfolio snapshot"""
    try:
        conn = get_db()
        cursor = conn.cursor()
        cursor.execute('''
            SELECT timestamp, cash_brl, total_value_brl, runway_months, holdings_json
            FROM portfolio_snapshots
            ORDER BY id DESC
            LIMIT 1
        ''')

        row = cursor.fetchone()
        conn.close()

        if row:
            return {
                'timestamp': row[0],
                'cash': row[1],
                'total_value': row[2],
                'runway_months': row[3],
                'holdings': json.loads(row[4])
            }
        else:
            return {'cash': 140000, 'holdings': {coin: 0 for coin in COINS}, 'total_value': 140000, 'runway_months': 17.5}
    except Exception as e:
        print(f"❌ Error fetching portfolio: {e}")
        return {'cash': 140000, 'holdings': {}, 'total_value': 140000, 'runway_months': 17.5}

def fetch_price_history(hours=1) -> List[Dict]:
    """Fetch price history from database"""
    try:
        conn = get_db()
        cursor = conn.cursor()
        since = (datetime.now() - timedelta(hours=hours)).isoformat()

        cursor.execute('''
            SELECT timestamp, coin, price_usd, change_1h
            FROM price_history
            WHERE timestamp > ?
            ORDER BY timestamp ASC
        ''', (since,))

        prices = []
        for row in cursor.fetchall():
            prices.append({
                'timestamp': row[0],
                'coin': row[1],
                'price_usd': row[2],
                'change_1h': row[3]
            })

        conn.close()
        return prices
    except Exception as e:
        print(f"❌ Error fetching price history: {e}")
        return []

# ========== PRICE FETCHING ==========

def fetch_current_prices() -> Dict:
    """Fetch current prices from CoinGecko"""
    try:
        markets = cg.get_coins_markets(
            vs_currency='usd',
            ids=','.join(COINS),
            price_change_percentage='1h,24h',
            per_page=len(COINS),
            order='market_cap_desc'
        )

        prices = {}
        for market in markets:
            coin_id = market['id']
            prices[coin_id] = {
                'price': market.get('current_price', 0) or 0,
                'change_1h': market.get('price_change_percentage_1h_in_currency', 0) or 0,
                'change_24h': market.get('price_change_percentage_24h', 0) or 0,
                'market_cap': market.get('market_cap', 0) or 0,
                'volume_24h': market.get('total_volume', 0) or 0
            }

        return prices
    except Exception as e:
        print(f"❌ Error fetching prices: {e}")
        return {}

# ========== BACKGROUND UPDATES ==========

def update_loop():
    """Background thread to update prices and portfolio"""
    print("🔄 Update loop started")

    while True:
        try:
            # Fetch prices
            prices = fetch_current_prices()
            if prices:
                current_state['prices'] = prices
                current_state['last_update'] = datetime.now().isoformat()

                # Add to history
                history_entry = {'timestamp': current_state['last_update']}
                for coin, data in prices.items():
                    history_entry[coin] = data['price']

                history['prices'].append(history_entry)
                if len(history['prices']) > MAX_HISTORY:
                    history['prices'] = history['prices'][-MAX_HISTORY:]

            # Fetch portfolio
            portfolio = fetch_portfolio_snapshot()
            current_state['portfolio'] = portfolio

            # Add to portfolio history
            history['portfolio'].append({
                'timestamp': datetime.now().isoformat(),
                'total_value': portfolio.get('total_value', 0),
                'cash': portfolio.get('cash', 0),
                'holdings': portfolio.get('holdings', {})
            })
            if len(history['portfolio']) > MAX_HISTORY:
                history['portfolio'] = history['portfolio'][-MAX_HISTORY:]

            # Fetch recent trades
            trades = fetch_recent_trades(20)
            history['trades'] = trades

            # Broadcast update via WebSocket
            socketio.emit('update', {
                'prices': current_state['prices'],
                'portfolio': current_state['portfolio'],
                'recent_trades': trades[:5],  # Last 5 trades
                'timestamp': current_state['last_update']
            }, namespace='/', broadcast=True)

            print(f"✅ Update broadcasted at {current_state['last_update']}")

        except Exception as e:
            print(f"❌ Update loop error: {e}")

        time.sleep(CHECK_INTERVAL)

# ========== HTTP ENDPOINTS ==========

@app.route('/api/status', methods=['GET'])
def api_status():
    """Get bot status"""
    portfolio = current_state['portfolio']
    return jsonify({
        'status': 'running' if current_state['bot_running'] else 'idle',
        'last_update': current_state['last_update'],
        'portfolio': {
            'total_value': portfolio.get('total_value', 0),
            'cash': portfolio.get('cash', 0),
            'runway_months': portfolio.get('runway_months', 0)
        },
        'coins_tracking': COINS,
        'check_interval': CHECK_INTERVAL
    })

@app.route('/api/portfolio', methods=['GET'])
def api_portfolio():
    """Get full portfolio details"""
    return jsonify(current_state['portfolio'])

@app.route('/api/prices', methods=['GET'])
def api_prices():
    """Get current prices"""
    return jsonify(current_state['prices'])

@app.route('/api/trades', methods=['GET'])
def api_trades():
    """Get trade history"""
    limit = int(request.args.get('limit', 100))
    trades = fetch_recent_trades(limit)
    return jsonify({'trades': trades, 'count': len(trades)})

@app.route('/api/history/prices', methods=['GET'])
def api_price_history():
    """Get price history"""
    hours = int(request.args.get('hours', 1))
    prices = fetch_price_history(hours)
    return jsonify({'prices': prices, 'count': len(prices)})

@app.route('/api/history/portfolio', methods=['GET'])
def api_portfolio_history():
    """Get portfolio history"""
    return jsonify({'history': history['portfolio'], 'count': len(history['portfolio'])})

@app.route('/api/grok-insights', methods=['GET'])
def api_grok_insights():
    """Get recent Grok insights from trades"""
    trades = fetch_recent_trades(10)
    insights = [
        {
            'timestamp': t['timestamp'],
            'coin': t['coin'],
            'action': t['action'],
            'reason': t['grok_reason']
        }
        for t in trades if t.get('grok_reason')
    ]
    return jsonify({'insights': insights, 'count': len(insights)})

@app.route('/health', methods=['GET'])
def health():
    """Health check endpoint"""
    return jsonify({
        'status': 'healthy',
        'service': 'crypto-grok-server',
        'version': '1.0',
        'timestamp': datetime.now().isoformat()
    })

# ========== WEBSOCKET EVENTS ==========

@socketio.on('connect')
def handle_connect():
    """Client connected"""
    print(f"🔌 Client connected: {request.sid}")

    # Send initial state
    emit('initial_state', {
        'prices': current_state['prices'],
        'portfolio': current_state['portfolio'],
        'recent_trades': history['trades'][:5],
        'timestamp': current_state['last_update']
    })

@socketio.on('disconnect')
def handle_disconnect():
    """Client disconnected"""
    print(f"🔌 Client disconnected: {request.sid}")

@socketio.on('request_update')
def handle_request_update():
    """Client requested manual update"""
    print(f"🔄 Manual update requested by {request.sid}")

    # Fetch fresh data
    prices = fetch_current_prices()
    portfolio = fetch_portfolio_snapshot()
    trades = fetch_recent_trades(5)

    emit('update', {
        'prices': prices,
        'portfolio': portfolio,
        'recent_trades': trades,
        'timestamp': datetime.now().isoformat()
    })

# ========== STARTUP ==========

def start_server():
    """Start Flask + SocketIO server"""
    print("=" * 60)
    print("🚀 GROK CRYPTO BOT - WEBSOCKET SERVER v1.0")
    print("=" * 60)
    print(f"📡 Port: 9003")
    print(f"🌐 CORS: localhost + Tailscale (100.75.88.8)")
    print(f"💾 Database: {DB_PATH}")
    print(f"🪙 Tracking: {', '.join([c.upper() for c in COINS])}")
    print(f"⏱️ Update interval: {CHECK_INTERVAL}s")
    print("=" * 60)

    # Start background update thread
    update_thread = threading.Thread(target=update_loop, daemon=True)
    update_thread.start()

    # Start Flask-SocketIO server
    socketio.run(
        app,
        host='0.0.0.0',
        port=9003,
        debug=False,
        allow_unsafe_werkzeug=True
    )

if __name__ == "__main__":
    start_server()
