"""
HTTP client for communicating with AgentNEX Backend
"""

import asyncio
import logging
from typing import Any, Dict, List, Optional
from urllib.parse import urljoin

import httpx
from pydantic import BaseModel

from app.core.config import settings
from app.core.exceptions import (
    BackendConnectionError,
    AuthenticationError,
    DeviceNotFoundError,
    MCPServerError
)


logger = logging.getLogger(__name__)


class BackendClient:
    """HTTP client for AgentNEX Backend internal APIs"""
    
    def __init__(self):
        self.base_url = settings.agentnex_backend_url.rstrip('/')
        self.api_key = settings.agentnex_api_key
        self.timeout = settings.agentnex_backend_timeout
        self.retry_attempts = settings.agentnex_backend_retry_attempts
        self.retry_delay = settings.agentnex_backend_retry_delay
        
        # HTTP client configuration
        self.headers = {
            "X-API-Key": self.api_key,
            "Content-Type": "application/json",
            "User-Agent": f"{settings.agentnex_mcp_server_name}/{settings.agentnex_mcp_server_version}"
        }
        
    async def _make_request(
        self, 
        method: str, 
        endpoint: str, 
        **kwargs
    ) -> Dict[str, Any]:
        """Make HTTP request with retry logic.

        Endpoints are relative to base_url (e.g. /api/health, /api/internal/devices).
        base_url must be the backend origin only (no path), e.g. https://host.run.app
        """
        url = urljoin(f"{self.base_url}/", endpoint.lstrip('/'))
        
        for attempt in range(self.retry_attempts + 1):
            try:
                async with httpx.AsyncClient(timeout=self.timeout) as client:
                    response = await client.request(
                        method=method,
                        url=url,
                        headers=self.headers,
                        **kwargs
                    )
                    
                    # Handle HTTP errors
                    if response.status_code == 401:
                        raise AuthenticationError("Invalid API key")
                    elif response.status_code == 404:
                        raise DeviceNotFoundError("Device not found or offline")
                    elif response.status_code >= 400:
                        error_msg = f"HTTP {response.status_code}: {response.text}"
                        raise BackendConnectionError(error_msg)
                    
                    return response.json()
                    
            except httpx.TimeoutException:
                if attempt < self.retry_attempts:
                    logger.warning(f"Request timeout, retrying in {self.retry_delay}s (attempt {attempt + 1})")
                    await asyncio.sleep(self.retry_delay)
                    continue
                raise BackendConnectionError("Request timeout after retries")
                
            except httpx.ConnectError:
                if attempt < self.retry_attempts:
                    logger.warning(f"Connection failed, retrying in {self.retry_delay}s (attempt {attempt + 1})")
                    await asyncio.sleep(self.retry_delay)
                    continue
                raise BackendConnectionError("Failed to connect to backend")
                
            except Exception as e:
                if attempt < self.retry_attempts:
                    logger.warning(f"Request failed: {e}, retrying in {self.retry_delay}s")
                    await asyncio.sleep(self.retry_delay)
                    continue
                raise MCPServerError(f"Backend request failed: {e}")
    
    async def get_devices(self, organization_id: Optional[str] = None) -> List[Dict[str, Any]]:
        """Get list of devices"""
        params = {}
        if organization_id:
            params["organization_id"] = organization_id
            
        response = await self._make_request("GET", "/api/internal/devices", params=params)
        return response.get("devices", [])
    
    async def get_device(self, device_id: str) -> Dict[str, Any]:
        """Get device information"""
        response = await self._make_request("GET", f"/api/internal/devices/{device_id}")
        return response
    
    async def get_device_telemetry(self, device_id: str) -> Dict[str, Any]:
        """Get device telemetry data"""
        response = await self._make_request("GET", f"/api/internal/devices/{device_id}/telemetry")
        return response
    
    async def get_device_processes(self, device_id: str) -> List[Dict[str, Any]]:
        """Get device process list"""
        response = await self._make_request("GET", f"/api/internal/devices/{device_id}/processes")
        return response.get("processes", [])
    
    async def get_device_events(self, device_id: str, limit: int = 100) -> List[Dict[str, Any]]:
        """Get device event logs"""
        params = {"limit": limit}
        response = await self._make_request("GET", f"/api/internal/devices/{device_id}/events", params=params)
        return response.get("events", [])
    
    async def execute_action(self, device_id: str, action_data: Dict[str, Any]) -> Dict[str, Any]:
        """Execute action on device"""
        response = await self._make_request(
            "POST", 
            f"/api/internal/devices/{device_id}/actions",
            json=action_data
        )
        return response
    
    async def get_device_status(self, device_id: str) -> Dict[str, Any]:
        """Get device status"""
        response = await self._make_request("GET", f"/api/internal/devices/{device_id}/status")
        return response
    
    async def health_check(self) -> bool:
        """Check if backend is healthy"""
        try:
            await self._make_request("GET", "/api/health")
            return True
        except Exception:
            return False