"""
HTTP Client for QPredict server endpoints

This client handles all communication between the QGIS plugin and the server.
It ALWAYS uses the current server URL from QGeoAIClient (dynamic port).
"""

import sys
from pathlib import Path
from typing import Optional, Dict, Any, List
import requests

# Import QGeoAI client
qgeoai_path = str(Path.home() / '.qgeoai')
if qgeoai_path not in sys.path:
    sys.path.insert(0, qgeoai_path)

from qgeoai_client import QGeoAIClient


class QPredictClient:
    """
    Client for QPredict server API.
    
    This client uses QGeoAIClient for dynamic server URL discovery.
    It NEVER stores the server URL - it always gets it fresh from QGeoAIClient.
    """
    
    def __init__(self):
        """
        Initialize client.
        
        NO parameters - we get everything from QGeoAIClient dynamically.
        """
        # Create QGeoAI client for dynamic URL/token
        self.qgeoai_client = QGeoAIClient()
        self.session = requests.Session()
    
    @property
    def _server_url(self):
        """Get current server URL (dynamic)."""
        return self.qgeoai_client.base_url
    
    @property
    def _headers(self):
        """Get current headers with fresh token (dynamic)."""
        return self.qgeoai_client.headers
    
    def load_model(
        self, 
        qmtp_path: str, 
        device: str = 'cpu',
        cuda_device_id: int = 0
    ) -> tuple[bool, Optional[str], Optional[Dict[str, Any]]]:
        """
        Load a model on the server.
        
        Args:
            qmtp_path: Path to .qmtp file
            device: 'cpu' or 'cuda'
            cuda_device_id: CUDA device ID
        
        Returns:
            Tuple of (success, error_message, model_info)
        """
        url = f"{self._server_url}/qpredict/load-model"
        
        try:
            with open(qmtp_path, 'rb') as f:
                files = {'qmtp_file': f}
                data = {
                    'device': device.lower(),
                    'cuda_device_id': cuda_device_id
                }
                
                response = self.session.post(
                    url,
                    headers={'Authorization': self._headers.get('Authorization')},  # Only auth header for multipart
                    files=files,
                    data=data,
                    timeout=60
                )
                
                if response.status_code == 401:
                    return False, "Authentication failed. Server may have restarted.", None
                
                response.raise_for_status()
                model_info = response.json()
                
                return True, None, model_info
                
        except requests.exceptions.RequestException as e:
            return False, f"Failed to load model: {str(e)}", None
    
    def unload_model(self, model_id: str) -> tuple[bool, Optional[str]]:
        """Unload a model from the server."""
        url = f"{self._server_url}/qpredict/unload-model"
        
        try:
            response = self.session.post(
                url,
                headers=self._headers,
                json={'model_id': model_id},
                timeout=10
            )
            response.raise_for_status()
            return True, None
        except requests.exceptions.RequestException as e:
            return False, f"Failed to unload model: {str(e)}"
    
    def predict(
        self,
        model_id: str,
        tiles: List[str],
        tile_metadata: List[Dict],
        output_shape: tuple,
        batch_size: int,
        **kwargs
    ) -> tuple[bool, Optional[str], Optional[Dict[str, Any]]]:
        """
        Run prediction on tiles.
        
        Args:
            model_id: Model UUID
            tiles: List of base64-encoded tiles
            tile_metadata: List of tile metadata dicts
            output_shape: (height, width)
            batch_size: Batch size
            **kwargs: Task-specific parameters
        
        Returns:
            Tuple of (success, error_message, result)
        """
        url = f"{self._server_url}/qpredict/predict"
        
        payload = {
            'model_id': model_id,
            'tiles': tiles,
            'tile_metadata': tile_metadata,
            'output_shape': output_shape,
            'batch_size': batch_size,
            **kwargs
        }
        
        try:
            response = self.session.post(
                url,
                headers=self._headers,
                json=payload,
                timeout=300
            )
            
            response.raise_for_status()
            result = response.json()
            
            return True, None, result
            
        except requests.exceptions.RequestException as e:
            return False, f"Prediction failed: {str(e)}", None