"""SILICO Bot client for trading strategy integration."""
import socket
from typing import Optional, Dict, Any
import requests

from .models import TradeRequest, TradeResponse, MarketData
from .exceptions import (
    AuthenticationError,
    RateLimitError,
    NetworkError,
    SilicoError,
)


class SilicoBot:
    """
    Main client for interacting with SILICO trading platform.

    Example:
        >>> bot = SilicoBot(api_key="sk_xxx")
        >>> bot.buy("SOL/USDC", amount_usdc=100)
    """

    def __init__(
        self,
        api_key: str,
        base_url: Optional[str] = None,
        timeout: int = 30
    ):
        """
        Initialize SILICO bot client.

        Args:
            api_key: Your SILICO API key (get from dashboard)
            base_url: Optional API base URL (auto-detected if not provided)
            timeout: Request timeout in seconds (default: 30)
        """
        self.api_key = api_key
        self.base_url = base_url or self._detect_base_url()
        self.timeout = timeout
        self.market = MarketData()

        # Request session for connection pooling
        self._session = requests.Session()
        self._session.headers.update({
            "X-API-Key": self.api_key,
            "Content-Type": "application/json",
            "User-Agent": "silico-python-sdk/0.1.0"
        })

    def _detect_base_url(self) -> str:
        """
        Auto-detect API base URL.

        Checks if localhost:8000 is reachable, otherwise uses production.

        Returns:
            Base URL for API requests
        """
        # Try localhost first for development
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(0.5)

        try:
            result = sock.connect_ex(("localhost", 8000))
            if result == 0:
                return "http://localhost:8000"
        except Exception:
            pass
        finally:
            sock.close()

        # Fall back to production
        return "https://api.silico.fun"

    def _request(
        self,
        method: str,
        endpoint: str,
        data: Optional[Dict] = None,
        params: Optional[Dict] = None
    ) -> Dict[str, Any]:
        """
        Make HTTP request to SILICO API.

        Args:
            method: HTTP method (GET, POST, etc.)
            endpoint: API endpoint path
            data: Request body (for POST)
            params: Query parameters (for GET)

        Returns:
            Parsed JSON response

        Raises:
            AuthenticationError: Invalid API key
            RateLimitError: Rate limit exceeded
            NetworkError: Connection failed
            SilicoError: Other API errors
        """
        url = f"{self.base_url}{endpoint}"

        try:
            response = self._session.request(
                method=method,
                url=url,
                json=data,
                params=params,
                timeout=self.timeout
            )

            # Handle HTTP errors
            if response.status_code == 401:
                raise AuthenticationError(
                    "Invalid API key. Get yours at https://silico.fun/dashboard"
                )

            elif response.status_code == 429:
                # Parse rate limit info
                body = response.json()
                detail = body.get("detail", {})

                if isinstance(detail, dict):
                    retry_after = detail.get("retry_after_seconds")
                    raise RateLimitError(
                        "Rate limit exceeded",
                        retry_after=retry_after
                    )
                else:
                    raise RateLimitError(str(detail))

            elif response.status_code >= 500:
                raise NetworkError(
                    f"Server error: {response.status_code}"
                )

            elif response.status_code >= 400:
                body = response.json()
                raise SilicoError(body.get("detail", "Unknown error"))

            return response.json()

        except requests.exceptions.Timeout:
            raise NetworkError("Request timeout")

        except requests.exceptions.ConnectionError:
            raise NetworkError("Connection failed")

        except requests.exceptions.RequestException as e:
            raise NetworkError(f"Network error: {e}")

    def buy(
        self,
        symbol: str,
        amount_usdc: float,
        strategy_tag: Optional[str] = None,
        max_slippage_bps: int = 50
    ) -> TradeResponse:
        """
        Execute a BUY trade.

        Args:
            symbol: Trading pair (e.g., "SOL/USDC")
            amount_usdc: Amount to buy in USDC
            strategy_tag: Optional strategy identifier
            max_slippage_bps: Max slippage in basis points

        Returns:
            TradeResponse with execution details

        Raises:
            AuthenticationError: Invalid API key
            RateLimitError: Too many requests
            InsufficientBalanceError: Not enough balance
        """
        request = TradeRequest(
            symbol=symbol,
            side="BUY",
            amount_usdc=amount_usdc,
            strategy_tag=strategy_tag,
            max_slippage_bps=max_slippage_bps
        )

        response = self._request(
            method="POST",
            endpoint="/api/trade/execute",
            data=request.to_dict()
        )

        return TradeResponse.from_api_response(response)

    def sell(
        self,
        symbol: str,
        amount_usdc: float,
        strategy_tag: Optional[str] = None,
        max_slippage_bps: int = 50
    ) -> TradeResponse:
        """
        Execute a SELL trade.

        Args:
            symbol: Trading pair (e.g., "SOL/USDC")
            amount_usdc: Amount to sell in USDC
            strategy_tag: Optional strategy identifier
            max_slippage_bps: Max slippage in basis points

        Returns:
            TradeResponse with execution details
        """
        request = TradeRequest(
            symbol=symbol,
            side="SELL",
            amount_usdc=amount_usdc,
            strategy_tag=strategy_tag,
            max_slippage_bps=max_slippage_bps
        )

        response = self._request(
            method="POST",
            endpoint="/api/trade/execute",
            data=request.to_dict()
        )

        return TradeResponse.from_api_response(response)

    def get_price(self, symbol: str) -> float:
        """
        Get current market price for a symbol.

        Args:
            symbol: Trading pair (e.g., "SOL/USDC")

        Returns:
            Current price
        """
        # Extract token from symbol (SOL/USDC -> SOL)
        token = symbol.split("/")[0]

        response = self._request(
            method="GET",
            endpoint="/api/market/quote",
            params={"token": token}
        )

        price = response["data"]["price"]

        # Update local market data cache
        self.market.update_price(symbol, price)

        return price
