"""
HTTP utility functions for API testing
"""
import requests
import time
from typing import Dict, Optional, Any, Tuple
from .logger import Logger


class HTTPUtils:
    """Helper functions for HTTP requests"""
    
    def __init__(self, logger: Logger, base_url: str = "http://localhost:8000"):
        self.logger = logger
        self.base_url = base_url
        self.session = requests.Session()
        self.access_token: Optional[str] = None
        self.refresh_token: Optional[str] = None
        self.last_response: Optional[requests.Response] = None
    
    def _make_request(
        self,
        method: str,
        endpoint: str,
        data: Optional[Dict] = None,
        json_data: Optional[Dict] = None,
        params: Optional[Dict] = None,
        headers: Optional[Dict] = None,
        timeout: int = 10
    ) -> Tuple[bool, int, Any]:
        """
        Make HTTP request with retry logic

        Returns:
            Tuple of (success, status_code, response_data)
        """
        url = f"{self.base_url}{endpoint}"

        # Add auth header if we have a token
        request_headers = headers or {}
        if self.access_token:
            request_headers["Authorization"] = f"Bearer {self.access_token}"

        # Retry logic with exponential backoff
        max_retries = 3
        retry_delay = 1

        for attempt in range(max_retries):
            try:
                if method == "GET":
                    response = self.session.get(
                        url, params=params, headers=request_headers, timeout=timeout
                    )
                elif method == "POST":
                    response = self.session.post(
                        url, data=data, json=json_data, headers=request_headers, timeout=timeout
                    )
                elif method == "PUT":
                    response = self.session.put(
                        url, data=data, json=json_data, headers=request_headers, timeout=timeout
                    )
                elif method == "DELETE":
                    response = self.session.delete(
                        url, headers=request_headers, timeout=timeout
                    )
                else:
                    return False, 0, f"Unsupported method: {method}"

                # Store last response for header access
                self.last_response = response

                # Try to parse JSON response
                try:
                    response_data = response.json()
                except:
                    response_data = response.text

                return True, response.status_code, response_data
                
            except requests.exceptions.Timeout:
                if attempt < max_retries - 1:
                    self.logger.warning("HTTP", f"Request timeout, retrying in {retry_delay}s...")
                    time.sleep(retry_delay)
                    retry_delay *= 2
                else:
                    return False, 0, "Request timeout"
            except requests.exceptions.ConnectionError:
                if attempt < max_retries - 1:
                    self.logger.warning("HTTP", f"Connection error, retrying in {retry_delay}s...")
                    time.sleep(retry_delay)
                    retry_delay *= 2
                else:
                    return False, 0, "Connection error"
            except Exception as e:
                self.logger.error("HTTP", f"Request failed with exception: {type(e).__name__}: {e}")
                return False, 0, str(e)
        
        return False, 0, "Max retries exceeded"
    
    def get(self, endpoint: str, params: Optional[Dict] = None) -> Tuple[bool, int, Any]:
        """Make GET request"""
        return self._make_request("GET", endpoint, params=params)
    
    def post(self, endpoint: str, data: Optional[Dict] = None, json_data: Optional[Dict] = None) -> Tuple[bool, int, Any]:
        """Make POST request"""
        return self._make_request("POST", endpoint, data=data, json_data=json_data)
    
    def post_with_files(self, endpoint: str, data: Optional[Dict] = None, files: Optional[Dict] = None) -> Tuple[bool, int, Any]:
        """Make POST request with file upload"""
        url = f"{self.base_url}{endpoint}"
        
        # Add auth header if we have a token
        headers = {}
        if self.access_token:
            headers["Authorization"] = f"Bearer {self.access_token}"
        
        try:
            response = self.session.post(
                url, data=data, files=files, headers=headers, timeout=30
            )
            
            # Store last response for header access
            self.last_response = response
            
            # Try to parse JSON response
            try:
                response_data = response.json()
            except:
                response_data = response.text
            
            return True, response.status_code, response_data
        except Exception as e:
            return False, 0, str(e)
    
    def put(self, endpoint: str, data: Optional[Dict] = None, json_data: Optional[Dict] = None) -> Tuple[bool, int, Any]:
        """Make PUT request"""
        return self._make_request("PUT", endpoint, data=data, json_data=json_data)
    
    def delete(self, endpoint: str) -> Tuple[bool, int, Any]:
        """Make DELETE request"""
        return self._make_request("DELETE", endpoint)
    
    def request(self, method: str, endpoint: str, authenticated: bool = True, data: Optional[Dict] = None, json_data: Optional[Dict] = None, params: Optional[Dict] = None, headers: Optional[Dict] = None, timeout: int = 10) -> Tuple[bool, int, Any]:
        """Make HTTP request with optional authentication"""
        # Temporarily clear token if not authenticated
        temp_token = self.access_token
        if not authenticated:
            self.access_token = None
        
        result = self._make_request(method, endpoint, data=data, json_data=json_data, params=params, headers=headers, timeout=timeout)
        
        # Restore token
        self.access_token = temp_token
        
        return result
    
    def get_last_headers(self) -> Dict[str, str]:
        """Get headers from last response"""
        if self.last_response:
            return dict(self.last_response.headers)
        return {}
    
    def set_auth_token(self, access_token: str):
        """Set authentication token"""
        self.access_token = access_token
    
    def clear_auth_token(self):
        """Clear authentication token"""
        self.access_token = None
        self.refresh_token = None
    
    def check_url_accessible(self, url: str, timeout: int = 5) -> bool:
        """Check if a URL is accessible"""
        try:
            response = requests.get(url, timeout=timeout)
            return response.status_code < 500
        except:
            return False
    
    def check_port_open(self, host: str, port: int, timeout: int = 2) -> bool:
        """Check if a port is open"""
        try:
            import socket
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
                sock.settimeout(timeout)
                result = sock.connect_ex((host, port))
                return result == 0
        except:
            return False
