"""
API Tools

HTTP API operations for agents:
- REST API calls
- GraphQL queries
- Health checks
- Rate limiting aware requests
"""

from __future__ import annotations

import json
import logging
import time
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any

logger = logging.getLogger(__name__)


@dataclass
class APICallResult:
    """Result of an API call."""
    success: bool
    status_code: int | None = None
    response: Any = None
    error: str | None = None
    duration_ms: float = 0.0
    called_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))


class APITools:
    """Tools for making HTTP API calls."""

    def __init__(
        self,
        default_timeout: float = 30.0,
        max_retries: int = 3,
        rate_limit_per_second: float | None = None,
    ):
        """
        Initialize API tools.

        Args:
            default_timeout: Default request timeout in seconds
            max_retries: Maximum retry attempts for failed requests
            rate_limit_per_second: Rate limit (requests per second)
        """
        self.default_timeout = default_timeout
        self.max_retries = max_retries
        self.rate_limit_per_second = rate_limit_per_second
        self._last_request_time: float = 0
        self._call_history: list[APICallResult] = []
        logger.info("APITools initialized")

    async def _rate_limit_wait(self) -> None:
        """Wait if needed for rate limiting."""
        if self.rate_limit_per_second:
            min_interval = 1.0 / self.rate_limit_per_second
            elapsed = time.time() - self._last_request_time
            if elapsed < min_interval:
                await asyncio.sleep(min_interval - elapsed)
            self._last_request_time = time.time()

    async def get(
        self,
        url: str,
        headers: dict[str, str] | None = None,
        params: dict[str, Any] | None = None,
        timeout: float | None = None,
    ) -> dict[str, Any]:
        """
        Make a GET request.

        Args:
            url: Request URL
            headers: Request headers
            params: Query parameters
            timeout: Request timeout
        """
        import asyncio
        import httpx

        await self._rate_limit_wait()
        start_time = time.time()

        try:
            async with httpx.AsyncClient() as client:
                response = await client.get(
                    url,
                    headers=headers or {},
                    params=params or {},
                    timeout=timeout or self.default_timeout,
                )

            duration_ms = (time.time() - start_time) * 1000

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

            result = APICallResult(
                success=response.is_success,
                status_code=response.status_code,
                response=data,
                duration_ms=duration_ms,
            )
            self._call_history.append(result)

            return {
                "success": response.is_success,
                "status_code": response.status_code,
                "data": data,
                "duration_ms": duration_ms,
            }

        except Exception as e:
            duration_ms = (time.time() - start_time) * 1000
            result = APICallResult(
                success=False,
                error=str(e),
                duration_ms=duration_ms,
            )
            self._call_history.append(result)
            return {"success": False, "error": str(e), "duration_ms": duration_ms}

    async def post(
        self,
        url: str,
        data: dict[str, Any] | None = None,
        json_body: dict[str, Any] | None = None,
        headers: dict[str, str] | None = None,
        timeout: float | None = None,
    ) -> dict[str, Any]:
        """
        Make a POST request.

        Args:
            url: Request URL
            data: Form data
            json_body: JSON body
            headers: Request headers
            timeout: Request timeout
        """
        import asyncio
        import httpx

        await self._rate_limit_wait()
        start_time = time.time()

        try:
            async with httpx.AsyncClient() as client:
                response = await client.post(
                    url,
                    data=data,
                    json=json_body,
                    headers=headers or {},
                    timeout=timeout or self.default_timeout,
                )

            duration_ms = (time.time() - start_time) * 1000

            try:
                resp_data = response.json()
            except json.JSONDecodeError:
                resp_data = response.text

            result = APICallResult(
                success=response.is_success,
                status_code=response.status_code,
                response=resp_data,
                duration_ms=duration_ms,
            )
            self._call_history.append(result)

            return {
                "success": response.is_success,
                "status_code": response.status_code,
                "data": resp_data,
                "duration_ms": duration_ms,
            }

        except Exception as e:
            duration_ms = (time.time() - start_time) * 1000
            return {"success": False, "error": str(e), "duration_ms": duration_ms}

    async def graphql(
        self,
        url: str,
        query: str,
        variables: dict[str, Any] | None = None,
        headers: dict[str, str] | None = None,
        timeout: float | None = None,
    ) -> dict[str, Any]:
        """
        Make a GraphQL query.

        Args:
            url: GraphQL endpoint URL
            query: GraphQL query string
            variables: Query variables
            headers: Request headers
            timeout: Request timeout
        """
        payload = {
            "query": query,
            "variables": variables or {},
        }

        return await self.post(
            url,
            json_body=payload,
            headers={**(headers or {}), "Content-Type": "application/json"},
            timeout=timeout,
        )

    async def health_check(
        self,
        url: str,
        expected_status: int = 200,
        timeout: float = 5.0,
    ) -> dict[str, Any]:
        """
        Check if an API endpoint is healthy.

        Args:
            url: Health check URL
            expected_status: Expected HTTP status code
            timeout: Request timeout
        """
        result = await self.get(url, timeout=timeout)

        is_healthy = (
            result.get("success", False) and
            result.get("status_code") == expected_status
        )

        return {
            "url": url,
            "healthy": is_healthy,
            "status_code": result.get("status_code"),
            "duration_ms": result.get("duration_ms"),
            "error": result.get("error"),
        }

    async def batch_health_check(
        self,
        urls: list[str],
        expected_status: int = 200,
        timeout: float = 5.0,
    ) -> dict[str, Any]:
        """
        Check health of multiple endpoints.

        Args:
            urls: List of URLs to check
            expected_status: Expected HTTP status code
            timeout: Request timeout per URL
        """
        import asyncio

        results = await asyncio.gather(*[
            self.health_check(url, expected_status, timeout)
            for url in urls
        ])

        healthy_count = sum(1 for r in results if r.get("healthy"))

        return {
            "total": len(urls),
            "healthy": healthy_count,
            "unhealthy": len(urls) - healthy_count,
            "results": results,
        }

    def get_call_stats(self) -> dict[str, Any]:
        """Get API call statistics."""
        if not self._call_history:
            return {
                "total_calls": 0,
                "success_rate": 0.0,
                "avg_duration_ms": 0.0,
            }

        successful = sum(1 for c in self._call_history if c.success)
        avg_duration = sum(c.duration_ms for c in self._call_history) / len(self._call_history)

        return {
            "total_calls": len(self._call_history),
            "successful": successful,
            "failed": len(self._call_history) - successful,
            "success_rate": successful / len(self._call_history),
            "avg_duration_ms": avg_duration,
        }


# Tool definitions for Claude Agent SDK
API_TOOLS = [
    {
        "name": "api_get",
        "description": "Make an HTTP GET request to an API.",
        "input_schema": {
            "type": "object",
            "properties": {
                "url": {"type": "string", "description": "Request URL"},
                "headers": {"type": "object", "description": "Request headers"},
                "params": {"type": "object", "description": "Query parameters"},
                "timeout": {"type": "number", "description": "Timeout in seconds"},
            },
            "required": ["url"],
        },
    },
    {
        "name": "api_post",
        "description": "Make an HTTP POST request to an API.",
        "input_schema": {
            "type": "object",
            "properties": {
                "url": {"type": "string", "description": "Request URL"},
                "json_body": {"type": "object", "description": "JSON body"},
                "headers": {"type": "object", "description": "Request headers"},
                "timeout": {"type": "number", "description": "Timeout in seconds"},
            },
            "required": ["url"],
        },
    },
    {
        "name": "api_graphql",
        "description": "Make a GraphQL query.",
        "input_schema": {
            "type": "object",
            "properties": {
                "url": {"type": "string", "description": "GraphQL endpoint URL"},
                "query": {"type": "string", "description": "GraphQL query"},
                "variables": {"type": "object", "description": "Query variables"},
                "headers": {"type": "object", "description": "Request headers"},
            },
            "required": ["url", "query"],
        },
    },
    {
        "name": "api_health_check",
        "description": "Check if an API endpoint is healthy.",
        "input_schema": {
            "type": "object",
            "properties": {
                "url": {"type": "string", "description": "Health check URL"},
                "expected_status": {"type": "integer", "description": "Expected status code", "default": 200},
                "timeout": {"type": "number", "description": "Timeout in seconds", "default": 5.0},
            },
            "required": ["url"],
        },
    },
    {
        "name": "api_batch_health_check",
        "description": "Check health of multiple API endpoints.",
        "input_schema": {
            "type": "object",
            "properties": {
                "urls": {"type": "array", "items": {"type": "string"}, "description": "URLs to check"},
                "expected_status": {"type": "integer", "description": "Expected status code", "default": 200},
            },
            "required": ["urls"],
        },
    },
    {
        "name": "api_call_stats",
        "description": "Get API call statistics.",
        "input_schema": {"type": "object", "properties": {}},
    },
]


__all__ = ["APITools", "API_TOOLS"]
