"""Async HTTP client for communicating with the LetsBe Hub."""

import asyncio
from typing import Any, Optional

import httpx

from app.config import Settings, get_settings
from app.utils.credential_reader import get_all_tool_credentials, get_credential_hash
from app.utils.logger import get_logger

logger = get_logger("hub_client")


class HubClient:
    """Async client for Hub REST API.

    Used for sending heartbeats with tool credentials directly to the Hub.
    This bypasses the orchestrator for credential synchronization.
    """

    def __init__(self, settings: Optional[Settings] = None):
        self.settings = settings or get_settings()
        self._client: Optional[httpx.AsyncClient] = None
        self._last_credentials_hash: str = ""

    @property
    def is_configured(self) -> bool:
        """Check if Hub connection is configured."""
        return bool(
            self.settings.hub_url
            and self.settings.hub_api_key
            and self.settings.hub_telemetry_enabled
        )

    def _get_headers(self) -> dict[str, str]:
        """Get headers for Hub API requests."""
        return {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.settings.hub_api_key}",
            "X-Agent-Version": self.settings.agent_version,
            "X-Agent-Hostname": self.settings.hostname,
        }

    async def _get_client(self) -> httpx.AsyncClient:
        """Get or create the HTTP client."""
        if self._client is None or self._client.is_closed:
            self._client = httpx.AsyncClient(
                base_url=self.settings.hub_url,
                headers=self._get_headers(),
                timeout=httpx.Timeout(30.0, connect=10.0),
            )
        return self._client

    async def send_heartbeat(
        self,
        include_credentials: bool = True,
        status: Optional[dict[str, Any]] = None,
    ) -> bool:
        """Send heartbeat to Hub with optional credentials.

        Args:
            include_credentials: Include tool credentials in heartbeat
            status: Optional system status metrics

        Returns:
            True if heartbeat was sent successfully
        """
        if not self.is_configured:
            logger.debug("hub_heartbeat_skipped", reason="not_configured")
            return False

        try:
            payload: dict[str, Any] = {
                "agentVersion": self.settings.agent_version,
            }

            # Include system status if provided
            if status:
                payload["status"] = status

            # Include tool credentials only when they've changed
            if include_credentials:
                current_hash = get_credential_hash()
                if current_hash and current_hash != self._last_credentials_hash:
                    credentials = get_all_tool_credentials()
                    if credentials:
                        payload["credentials"] = credentials
                        payload["credentialsHash"] = current_hash
                        self._last_credentials_hash = current_hash
                        logger.debug(
                            "hub_heartbeat_with_credentials",
                            tools=list(credentials.keys()),
                        )
                elif current_hash:
                    # Just send the hash so Hub knows credentials haven't changed
                    payload["credentialsHash"] = current_hash

            client = await self._get_client()
            response = await client.post(
                "/api/v1/orchestrator/heartbeat",
                json=payload,
            )

            if response.status_code == 200:
                data = response.json()
                logger.info(
                    "hub_heartbeat_sent",
                    server_id=data.get("serverId"),
                    commands_pending=len(data.get("commands", [])),
                )
                return True
            elif response.status_code == 401:
                logger.warning(
                    "hub_heartbeat_auth_failed",
                    status_code=response.status_code,
                )
                return False
            else:
                logger.warning(
                    "hub_heartbeat_failed",
                    status_code=response.status_code,
                    response=response.text[:200],
                )
                return False

        except (httpx.ConnectError, httpx.TimeoutException) as e:
            logger.warning("hub_heartbeat_network_error", error=str(e))
            return False
        except Exception as e:
            logger.error("hub_heartbeat_error", error=str(e))
            return False

    async def close(self) -> None:
        """Close the HTTP client."""
        if self._client and not self._client.is_closed:
            await self._client.aclose()
            self._client = None


# Singleton instance
_hub_client: Optional[HubClient] = None


def get_hub_client() -> HubClient:
    """Get the singleton Hub client instance."""
    global _hub_client
    if _hub_client is None:
        _hub_client = HubClient()
    return _hub_client


async def send_hub_heartbeat() -> bool:
    """Convenience function to send heartbeat to Hub.

    Returns:
        True if heartbeat was sent successfully, False if not configured or failed
    """
    client = get_hub_client()
    return await client.send_heartbeat()
