"""HTTP client for communicating with Maxtest API."""

import logging
from pathlib import Path
from typing import Optional, Dict, Any
import requests
from requests.exceptions import RequestException, Timeout, ConnectionError as RequestsConnectionError

from .config import MaxtestConfig
from .exceptions import AuthenticationError, UploadError, NetworkError

logger = logging.getLogger(__name__)


class MaxtestClient:
    """HTTP client for Maxtest API interactions."""
    
    def __init__(self, config: MaxtestConfig):
        """
        Initialize the Maxtest client.
        
        Args:
            config: Configuration object
        """
        self.config = config
        self.session = requests.Session()
        self.session.headers.update({
            "X-API-Key": config.api_key,
            "User-Agent": "maxtest-bridge-python/0.1.0"
        })
    
    def upload_results(
        self,
        zip_file_path: Path,
        metadata: Optional[Dict[str, Any]] = None
    ) -> Dict[str, Any]:
        """
        Upload test results to Maxtest.
        
        Args:
            zip_file_path: Path to the ZIP file containing allure-results
            metadata: Additional metadata to send with the upload
            
        Returns:
            Dict containing the API response
            
        Raises:
            AuthenticationError: If authentication fails (401)
            UploadError: If upload fails but should not break pipeline
            NetworkError: If network communication fails
        """
        endpoint = f"{self.config.base_url.rstrip('/')}/api/v1/automation/launches/upload"
        
        # Prepare metadata
        metadata = metadata or {}
        
        # Add API key to metadata (required by backend)
        metadata["api_key"] = self.config.api_key
        
        # Add other metadata fields
        metadata.update({
            "project_id": self.config.project_id,
            "launch_name": self.config.launch_name,
            "launch_description": self.config.launch_description,
            "environment": self.config.environment,
            "version": self.config.version,
            "test_plan_id": self.config.test_plan_id,
        })
        
        # Remove None values
        metadata = {k: v for k, v in metadata.items() if v is not None}
        
        try:
            logger.info(f"Uploading results to {endpoint}")
            logger.debug(f"Metadata: {metadata}")
            
            with open(zip_file_path, 'rb') as f:
                files = {
                    'file': ('allure-results.zip', f, 'application/zip')
                }
                data = metadata
                
                response = self.session.post(
                    endpoint,
                    files=files,
                    data=data,
                    timeout=self.config.timeout
                )
            
            # Handle different response codes
            if response.status_code == 401:
                raise AuthenticationError(
                    "Authentication failed. Please check your API key.\n"
                    f"Response: {response.text}"
                )
            
            elif response.status_code in [500, 503]:
                error_msg = (
                    f"Maxtest server error ({response.status_code}). "
                    f"The test results could not be uploaded.\n"
                    f"Response: {response.text}"
                )
                logger.warning(error_msg)
                
                if self.config.fail_on_upload_error:
                    raise UploadError(error_msg)
                else:
                    logger.warning("Continuing without failing the pipeline.")
                    return {"status": "failed", "error": error_msg}
            
            elif response.status_code >= 400:
                error_msg = (
                    f"Upload failed with status {response.status_code}.\n"
                    f"Response: {response.text}"
                )
                logger.error(error_msg)
                
                if self.config.fail_on_upload_error:
                    raise UploadError(error_msg)
                else:
                    logger.warning("Continuing without failing the pipeline.")
                    return {"status": "failed", "error": error_msg}
            
            # Success
            logger.info(f"✓ Results uploaded successfully (Status: {response.status_code})")
            
            try:
                response_data = response.json()
                
                # Display launch URL if available
                if response_data.get("launch_url"):
                    logger.info(f"🔗 View results: {response_data['launch_url']}")
                
                return response_data
            except ValueError:
                return {"status": "success", "message": response.text}
                
        except (Timeout, RequestsConnectionError) as e:
            error_msg = f"Network error while uploading results: {e}"
            logger.error(error_msg)
            
            if self.config.fail_on_upload_error:
                raise NetworkError(error_msg) from e
            else:
                logger.warning("Continuing without failing the pipeline.")
                return {"status": "failed", "error": error_msg}
                
        except RequestException as e:
            error_msg = f"Unexpected error during upload: {e}"
            logger.error(error_msg)
            
            if self.config.fail_on_upload_error:
                raise UploadError(error_msg) from e
            else:
                logger.warning("Continuing without failing the pipeline.")
                return {"status": "failed", "error": error_msg}
    
    def __enter__(self):
        """Context manager entry."""
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit."""
        self.session.close()
