"""
Core API Client for NWO Robotics CLI
"""

import os
import json
import requests
from typing import Optional, Dict, Any, List
from pathlib import Path
import yaml


class NWOAPIError(Exception):
    """Base exception for API errors"""
    def __init__(self, message: str, status_code: Optional[int] = None, response: Optional[Dict] = None):
        super().__init__(message)
        self.status_code = status_code
        self.response = response


class NWOClient:
    """HTTP client for NWO Robotics API"""
    
    BASE_URL = "https://nwo.capital/webapp"
    
    def __init__(self, api_key: Optional[str] = None):
        self.api_key = api_key or self._load_api_key()
        if not self.api_key:
            raise NWOAPIError(
                "No API key found. Run 'nwo auth login' or set NWO_API_KEY environment variable."
            )
        self.session = requests.Session()
        self.session.headers.update({
            "X-API-Key": self.api_key,
            "Content-Type": "application/json",
            "Accept": "application/json",
            "User-Agent": "NWO-CLI/2.0.0"
        })
    
    def _load_api_key(self) -> Optional[str]:
        """Load API key from environment or config file"""
        # Check environment first
        if os.getenv("NWO_API_KEY"):
            return os.getenv("NWO_API_KEY")
        
        # Check config file
        config_path = Path.home() / ".nwo" / "config.yaml"
        if config_path.exists():
            with open(config_path) as f:
                config = yaml.safe_load(f)
                return config.get("api_key")
        
        return None
    
    def _request(self, method: str, endpoint: str, **kwargs) -> Dict[str, Any]:
        """Make HTTP request to API"""
        url = f"{self.BASE_URL}/{endpoint}"
        
        try:
            response = self.session.request(method, url, timeout=30, **kwargs)
            
            # Handle non-JSON responses
            if response.status_code == 404:
                raise NWOAPIError(f"Endpoint not found: {endpoint}", 404)
            
            try:
                data = response.json()
            except json.JSONDecodeError:
                raise NWOAPIError(
                    f"Invalid JSON response: {response.text[:200]}",
                    response.status_code
                )
            
            if not response.ok:
                error_msg = data.get("error", "Unknown error")
                raise NWOAPIError(error_msg, response.status_code, data)
            
            return data
            
        except requests.exceptions.Timeout:
            raise NWOAPIError("Request timed out. API may be busy.")
        except requests.exceptions.ConnectionError:
            raise NWOAPIError("Cannot connect to API. Check your internet connection.")
    
    def get(self, endpoint: str, params: Optional[Dict] = None) -> Dict[str, Any]:
        """GET request"""
        return self._request("GET", endpoint, params=params)
    
    def post(self, endpoint: str, json_data: Optional[Dict] = None) -> Dict[str, Any]:
        """POST request"""
        return self._request("POST", endpoint, json=json_data)
    
    # ==================== API METHODS ====================
    
    def inference(self, instruction: str, image_url: Optional[str] = None, 
                  iot_sensors: Optional[Dict] = None) -> Dict[str, Any]:
        """Send inference request to robot"""
        payload = {"instruction": instruction}
        if image_url:
            payload["image_url"] = image_url
        if iot_sensors:
            payload["iot_sensors"] = iot_sensors
        
        return self.post("api-robotics.php?action=inference", payload)
    
    def health_check(self) -> Dict[str, Any]:
        """Check API health"""
        return self.get("api-robotics.php?action=health")
    
    def create_task_plan(self, instruction: str) -> Dict[str, Any]:
        """Create multi-step task plan"""
        return self.post("api-task-planner.php?action=plan", {"instruction": instruction})
    
    def get_learned_params(self, task_type: str, object_type: Optional[str] = None) -> Dict[str, Any]:
        """Get learned parameters from learning system"""
        payload = {"action": "get_parameters", "task_type": task_type}
        if object_type:
            payload["object_type"] = object_type
        return self.post("api-learning.php", payload)
    
    def list_models(self) -> Dict[str, Any]:
        """List configured models"""
        return self.post("api-model-manager.php?action=list_models", {})
    
    def preview_routing(self, instruction: str) -> Dict[str, Any]:
        """Preview which model would be selected"""
        return self.post("api-model-manager.php?action=preview_routing", {
            "instruction": instruction
        })
    
    def create_swarm(self, name: str, strategy: str = "divide_and_conquer",
                     coordinator_id: Optional[str] = None) -> Dict[str, Any]:
        """Create a new robot swarm"""
        payload = {
            "action": "create_swarm",
            "name": name,
            "strategy": strategy
        }
        if coordinator_id:
            payload["coordinator_agent_id"] = coordinator_id
        return self.post("api-coordination.php", payload)
    
    def add_to_swarm(self, swarm_id: str, agent_id: str) -> Dict[str, Any]:
        """Add agent to swarm"""
        return self.post("api-coordination.php", {
            "action": "add_agent",
            "swarm_id": swarm_id,
            "agent_id": agent_id
        })
    
    def detect_gesture(self, video_stream: str, gestures: List[str]) -> Dict[str, Any]:
        """Detect hand gestures"""
        return self.post("api-gesture.php?action=detect_gesture", {
            "video_stream": video_stream,
            "gestures": gestures
        })
    
    def process_voice(self, audio_data: str, wake_word: str = "Hey Robot") -> Dict[str, Any]:
        """Process voice command"""
        return self.post("api-voice.php?action=process_voice", {
            "audio": audio_data,
            "wake_word": wake_word
        })
    
    def subscribe_progress(self, task_id: str) -> Dict[str, Any]:
        """Subscribe to task progress updates"""
        return self.post("api-tasks.php?action=subscribe_progress", {
            "task_id": task_id
        })
    
    def configure_recovery(self, task_type: str, max_retries: int = 3) -> Dict[str, Any]:
        """Configure failure recovery strategies"""
        strategies = [
            {"angle_offset": 15},
            {"angle_offset": -15},
            {"grip_force": "increase"}
        ]
        return self.post("api-recovery.php?action=configure_recovery", {
            "task_type": task_type,
            "strategies": strategies,
            "max_retries": max_retries
        })
    
    def create_template(self, name: str, tasks: List[Dict], schedule: Optional[str] = None) -> Dict[str, Any]:
        """Create task template"""
        payload = {
            "action": "create_template",
            "name": name,
            "tasks": tasks
        }
        if schedule:
            payload["schedule"] = schedule
        return self.post("api-templates.php", payload)
    
    def simulate_trajectory(self, trajectory: List[List[float]], 
                           gravity: float = 9.81, mass: float = 0.5) -> Dict[str, Any]:
        """Simulate trajectory with physics"""
        return self.post("api-planning.php?action=simulate_trajectory", {
            "trajectory": trajectory,
            "physics_params": {
                "gravity": gravity,
                "object_mass": mass
            }
        })
    
    def enable_realtime_safety(self, agent_id: str, response_time_ms: int = 10) -> Dict[str, Any]:
        """Enable real-time safety monitoring"""
        return self.post("api-safety.php?action=enable_realtime_safety", {
            "agent_id": agent_id,
            "response_time_ms": response_time_ms,
            "safety_zones": {
                "danger": 0.5,
                "warning": 1.5
            }
        })
    
    def navigate_semantic(self, target: str, avoid: Optional[List[str]] = None) -> Dict[str, Any]:
        """Navigate using natural language"""
        payload = {"action": "navigate_semantic", "target": target}
        if avoid:
            payload["constraints"] = {"avoid": avoid, "prefer": "shortest"}
        return self.post("api-navigation.php", payload)
