#!/usr/bin/env python3
"""
AITBC Ollama Miner Plugin - Mines AITBC by processing LLM inference jobs
"""

import asyncio
import httpx
import logging
import json
import time
from datetime import datetime
from typing import Dict, Any, Optional

# Import the Ollama service
from service import ollama_service

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class OllamaMiner:
    """Miner plugin that processes LLM jobs using Ollama"""
    
    def __init__(self, coordinator_url: str, api_key: str, miner_id: str):
        self.coordinator_url = coordinator_url
        self.api_key = api_key
        self.miner_id = miner_id
        self.client = httpx.Client()
        self.running = False
        
    async def register(self):
        """Register the miner with Ollama capabilities"""
        
        # Get available models
        models = await ollama_service.get_models()
        model_list = [m["name"] for m in models]
        
        capabilities = {
            "service": "ollama",
            "gpu": {
                "model": "NVIDIA GeForce RTX 4060 Ti",
                "memory_gb": 16,
                "cuda_version": "12.1"
            },
            "ollama": {
                "models": model_list,
                "total_models": len(model_list),
                "supports_chat": True,
                "supports_generate": True
            },
            "compute": {
                "type": "GPU",
                "platform": "CUDA + Ollama",
                "supported_tasks": ["inference", "chat", "completion", "code-generation"],
                "max_concurrent_jobs": 2
            }
        }
        
        try:
            response = self.client.post(
                f"{self.coordinator_url}/v1/miners/register?miner_id={self.miner_id}",
                headers={
                    "Content-Type": "application/json",
                    "X-Api-Key": self.api_key
                },
                json={"capabilities": capabilities}
            )
            
            if response.status_code == 200:
                logger.info(f"✅ Registered Ollama miner with {len(model_list)} models")
                return True
            else:
                logger.error(f"❌ Registration failed: {response.status_code}")
                return False
                
        except Exception as e:
            logger.error(f"❌ Registration error: {e}")
            return False
    
    async def process_job(self, job: Dict[str, Any]) -> Dict[str, Any]:
        """Process an LLM inference job"""
        
        payload = job.get("payload", {})
        job_type = payload.get("type", "generate")
        model = payload.get("model", "llama3.2:latest")
        
        logger.info(f"Processing {job_type} job with model: {model}")
        
        try:
            if job_type == "generate":
                result = await ollama_service.generate(
                    model=model,
                    prompt=payload.get("prompt", ""),
                    system_prompt=payload.get("system_prompt"),
                    temperature=payload.get("temperature", 0.7),
                    max_tokens=payload.get("max_tokens")
                )
            elif job_type == "chat":
                result = await ollama_service.chat(
                    model=model,
                    messages=payload.get("messages", []),
                    temperature=payload.get("temperature", 0.7),
                    max_tokens=payload.get("max_tokens")
                )
            else:
                result = {
                    "success": False,
                    "error": f"Unknown job type: {job_type}"
                }
            
            if result["success"]:
                # Add job metadata
                result["job_id"] = job["job_id"]
                result["processed_at"] = datetime.now().isoformat()
                result["miner_id"] = self.miner_id
                
                # Calculate earnings (cost + markup)
                cost = result.get("cost", 0.001)
                earnings = cost * 1.5  # 50% markup
                result["aitbc_earned"] = earnings
                
                logger.info(f"✅ Job completed - Earned: {earnings} AITBC")
            
            return result
            
        except Exception as e:
            logger.error(f"❌ Job processing failed: {e}")
            return {
                "success": False,
                "error": str(e),
                "job_id": job["job_id"]
            }
    
    async def submit_result(self, job_id: str, result: Dict[str, Any]) -> bool:
        """Submit job result to coordinator"""
        
        payload = {
            "result": {
                "status": "completed" if result["success"] else "failed",
                "output": result.get("text", result.get("error", "")),
                "model": result.get("model"),
                "tokens": result.get("total_tokens", 0),
                "duration": result.get("duration_seconds", 0),
                "cost": result.get("cost", 0),
                "aitbc_earned": result.get("aitbc_earned", 0)
            },
            "metrics": {
                "compute_time": result.get("duration_seconds", 0),
                "energy_used": 0.05,
                "aitbc_earned": result.get("aitbc_earned", 0)
            }
        }
        
        try:
            response = self.client.post(
                f"{self.coordinator_url}/v1/miners/{job_id}/result",
                headers={
                    "Content-Type": "application/json",
                    "X-Api-Key": self.api_key
                },
                json=payload
            )
            
            return response.status_code == 200
            
        except Exception as e:
            logger.error(f"❌ Failed to submit result: {e}")
            return False
    
    async def send_heartbeat(self):
        """Send heartbeat with GPU stats"""
        
        # Get GPU utilization (simplified)
        heartbeat_data = {
            "status": "ONLINE",
            "inflight": 0,
            "metadata": {
                "last_seen": datetime.now().isoformat(),
                "gpu_utilization": 65,
                "gpu_memory_used": 10000,
                "gpu_temperature": 70,
                "ollama_models": len(await ollama_service.get_models()),
                "service": "ollama"
            }
        }
        
        try:
            response = self.client.post(
                f"{self.coordinator_url}/v1/miners/heartbeat?miner_id={self.miner_id}",
                headers={
                    "Content-Type": "application/json",
                    "X-Api-Key": self.api_key
                },
                json=heartbeat_data
            )
            
            return response.status_code == 200
            
        except Exception as e:
            logger.error(f"❌ Heartbeat failed: {e}")
            return False
    
    async def mine(self, max_jobs: Optional[int] = None):
        """Main mining loop"""
        
        logger.info("🚀 Starting Ollama miner...")
        
        # Register
        if not await self.register():
            return
        
        jobs_completed = 0
        last_heartbeat = time.time()
        
        self.running = True
        
        try:
            while self.running and (max_jobs is None or jobs_completed < max_jobs):
                
                # Send heartbeat every 30 seconds
                if time.time() - last_heartbeat > 30:
                    await self.send_heartbeat()
                    last_heartbeat = time.time()
                
                # Poll for jobs
                response = self.client.post(
                    f"{self.coordinator_url}/v1/miners/poll",
                    headers={
                        "Content-Type": "application/json",
                        "X-Api-Key": self.api_key
                    },
                    json={"max_wait_seconds": 5}
                )
                
                if response.status_code == 200:
                    job = response.json()
                    logger.info(f"📋 Got job: {job['job_id']}")
                    
                    # Process job
                    result = await self.process_job(job)
                    
                    # Submit result
                    if await self.submit_result(job['job_id'], result):
                        jobs_completed += 1
                        total_earned = sum(r.get("aitbc_earned", 0) for r in [result])
                        logger.info(f"💰 Total earned: {total_earned} AITBC")
                
                elif response.status_code == 204:
                    logger.debug("💤 No jobs available")
                    await asyncio.sleep(3)
                else:
                    logger.error(f"❌ Poll failed: {response.status_code}")
                    await asyncio.sleep(5)
                
        except KeyboardInterrupt:
            logger.info("⏹️  Mining stopped by user")
        
        finally:
            self.running = False
            logger.info(f"✅ Mining complete - Jobs processed: {jobs_completed}")

# Main execution
if __name__ == "__main__":
    import sys
    
    coordinator_url = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:8001"
    api_key = sys.argv[2] if len(sys.argv) > 2 else "${MINER_API_KEY}"
    miner_id = sys.argv[3] if len(sys.argv) > 3 else "ollama-miner"
    
    # Create and run miner
    miner = OllamaMiner(coordinator_url, api_key, miner_id)
    
    # Run the miner
    asyncio.run(miner.mine())
