import aiohttp
import logging
from typing import Optional, Dict
try:
    import orjson as json
    dumps = lambda x: json.dumps(x).decode('utf-8')
    loads = json.loads
except ImportError:
    try:
        import ujson as json
        dumps = json.dumps
        loads = json.loads
    except ImportError:
        import json
        dumps = json.dumps
        loads = json.loads

logger = logging.getLogger(__name__)


class Rest:
    """Optimized REST client with connection pooling."""

    __slots__ = ('salad', 'node', 'headers', 'session')

    def __init__(self, salad, node):
        self.salad = salad
        self.node = node
        self.headers = {
            'Authorization': node.auth,
            'User-Id': '',
            'Client-Name': node.clientName
        }
        self.session = None

    async def makeRequest(self, method: str, endpoint: str, data: Optional[Dict] = None):
        """Make HTTP request with connection pooling."""
        if not self.session or self.session.closed:
            timeout = aiohttp.ClientTimeout(total=30, connect=10)
            conn = aiohttp.TCPConnector(
                limit=100,
                limit_per_host=30,
                ttl_dns_cache=300
            )
            self.session = aiohttp.ClientSession(
                connector=conn,
                timeout=timeout,
                json_serialize=dumps
            )

        scheme = 'https' if self.node.ssl else 'http'
        url = f"{scheme}://{self.node.host}:{self.node.port}/{endpoint.lstrip('/')}"

        try:
            if method == 'GET':
                async with self.session.get(url, headers=self.headers) as resp:
                    if resp.status == 200:
                        body = await resp.read()
                        return loads(body) if body else None
                    return None

            elif method == 'POST':
                json_data = dumps(data).encode('utf-8') if data else b'{}'
                headers = {**self.headers, 'Content-Type': 'application/json'}
                async with self.session.post(url, data=json_data, headers=headers) as resp:
                    if resp.status in (200, 201):
                        body = await resp.read()
                        return loads(body) if body else None
                    return None

            elif method == 'PATCH':
                json_data = dumps(data).encode('utf-8') if data else b'{}'
                headers = {**self.headers, 'Content-Type': 'application/json'}
                async with self.session.patch(url, data=json_data, headers=headers) as resp:
                    if resp.status in (200, 201):
                        body = await resp.read()
                        return loads(body) if body else None
                    if resp.status == 204:
                        return None
                    return None

            elif method == 'DELETE':
                async with self.session.delete(url, headers=self.headers) as resp:
                    return resp.status in (200, 204)

        except Exception as e:
            logger.debug(f"Request failed: {e}")
            return None

    async def close(self) -> None:
        """Close session."""
        if self.session and not self.session.closed:
            await self.session.close()
