"""Utility functions for HLA-Compass SDK"""

import json
import logging
import time
from collections import deque
from threading import Lock
from typing import Any

logger = logging.getLogger(__name__)


def parse_api_error(response: Any, default_message: str) -> str:
    """
    Parse error message from API response.

    Args:
        response: HTTP response object
        default_message: Default message if parsing fails

    Returns:
        Sanitized error message
    """
    error_msg: Any = None
    try:
        if hasattr(response, "json"):
            error_data = response.json()
            if isinstance(error_data, dict):
                error_value = error_data.get("error")
                if isinstance(error_value, dict):
                    error_msg = error_value.get("message") or error_value.get("detail")
                elif isinstance(error_value, str):
                    error_msg = error_value

                if error_msg is None:
                    detail = error_data.get("detail")
                    if isinstance(detail, dict):
                        error_msg = detail.get("message")
                    elif isinstance(detail, str):
                        error_msg = detail

                if error_msg is None:
                    message = error_data.get("message")
                    if isinstance(message, str):
                        error_msg = message
            elif isinstance(error_data, str):
                error_msg = error_data
    except (json.JSONDecodeError, ValueError, AttributeError, TypeError):
        pass

    if isinstance(error_msg, str) and error_msg:
        if len(error_msg) > 500:
            error_msg = error_msg[:500] + "..."
        return error_msg

    # Return a generic message with status code if available
    if hasattr(response, "status_code"):
        return f"{default_message} (status: {response.status_code})"
    return default_message


class RateLimiter:
    """Simple rate limiter using a sliding window log algorithm"""

    def __init__(self, max_requests: int = 100, time_window: int = 60):
        """
        Initialize rate limiter.

        Args:
            max_requests: Maximum number of requests allowed
            time_window: Time window in seconds
        """
        self.max_requests = max_requests
        self.time_window = time_window
        self.requests: deque[float] = deque()
        self.lock = Lock()
        self.last_wait: float = 0.0

    def acquire(self, wait: bool = True, timeout: float = 30.0) -> bool:
        """
        Acquire permission to make a request.

        Args:
            wait: If True, wait until the request can be made
            timeout: Maximum seconds to wait (only when wait=True)

        Returns:
            True if the request can proceed, False otherwise
        """
        deadline = time.monotonic() + timeout
        while True:
            with self.lock:
                now = time.time()

                # Remove old requests outside the time window
                while self.requests and self.requests[0] <= now - self.time_window:
                    self.requests.popleft()

                # Check if we can make a request
                if len(self.requests) < self.max_requests:
                    self.requests.append(now)
                    self.last_wait = 0.0
                    return True

                if not wait:
                    return False

                if time.monotonic() >= deadline:
                    return False

                # Calculate remaining sleep time outside the critical section
                sleep_time = self.time_window - (now - self.requests[0]) + 0.1
                self.last_wait = max(sleep_time, 0.0)

            # Allow other threads to acquire while we sleep
            if sleep_time > 0:
                time.sleep(sleep_time)
            else:
                # If the queue is stale, loop again without sleeping
                time.sleep(0)
