"""
Feature 3:  Network agent communication (HTTP)
Feature 4:  WebSocket real-time communication
Feature 11: Agent registry over network
"""
import json
import threading
from typing import Optional
from http.server import HTTPServer, BaseHTTPRequestHandler


class AgentHandler(BaseHTTPRequestHandler):
    """HTTP handler for agent network communication."""

    def log_message(self, format, *args):
        pass  # Suppress default logging

    def do_GET(self):
        if self.path == "/health":
            self._respond(200, self.server.agent.health())
        elif self.path == "/card":
            self._respond(200, self.server.agent.card().to_dict())
        else:
            self._respond(404, {"error": "Not found"})

    def do_POST(self):
        if self.path == "/message":
            length = int(self.headers.get("Content-Length", 0))
            body = self.rfile.read(length)
            try:
                data = json.loads(body)
                content = data.get("content", "")
                messages = data.get("messages", [{"role": "user", "content": content}])
                response = self.server.agent.complete(messages)
                self._respond(200, {"response": response, "agent": self.server.agent.name})
            except Exception as e:
                self._respond(500, {"error": str(e)})
        else:
            self._respond(404, {"error": "Not found"})

    def _respond(self, status: int, data: dict):
        body = json.dumps(data).encode("utf-8")
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", len(body))
        self.end_headers()
        self.wfile.write(body)


class SynapseHTTPServer(HTTPServer):
    def __init__(self, agent, host: str, port: int):
        self.agent = agent
        super().__init__((host, port), AgentHandler)


class AgentServer:
    """
    Feature 3: Run any agent as a network HTTP service.

    Usage:
        server = AgentServer(agent, port=5001)
        server.start()  # runs in background thread
        server.stop()
    """

    def __init__(self, agent, port: int = 5000, host: str = "0.0.0.0"):
        self.agent = agent
        self.port = port
        self.host = host
        self._server: Optional[SynapseHTTPServer] = None
        self._thread: Optional[threading.Thread] = None
        self._running = False

    def start(self, blocking: bool = False):
        """Start the agent server."""
        self._server = SynapseHTTPServer(self.agent, self.host, self.port)
        self._running = True
        print(f"🌐 [{self.agent.name}] serving on http://{self.host}:{self.port}")

        if blocking:
            self._server.serve_forever()
        else:
            self._thread = threading.Thread(target=self._server.serve_forever, daemon=True)
            self._thread.start()

    def stop(self):
        if self._server:
            self._server.shutdown()
            self._running = False
            print(f"🛑 [{self.agent.name}] server stopped.")

    @property
    def url(self) -> str:
        return f"http://localhost:{self.port}"

    def __repr__(self):
        return f"AgentServer(agent={self.agent.name!r}, port={self.port}, running={self._running})"


class AgentClient:
    """
    Feature 3: Connect to a remote agent over HTTP.

    Usage:
        client = AgentClient("http://localhost:5001")
        response = client.send("Your message here")
    """

    def __init__(self, endpoint: str):
        self.endpoint = endpoint.rstrip("/")

    def send(self, message: str) -> str:
        import urllib.request
        url = f"{self.endpoint}/message"
        body = json.dumps({"content": message}).encode("utf-8")
        req = urllib.request.Request(
            url, data=body, method="POST",
            headers={"Content-Type": "application/json"}
        )
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read().decode("utf-8"))
            return data.get("response", "")

    def health(self) -> dict:
        import urllib.request
        url = f"{self.endpoint}/health"
        with urllib.request.urlopen(url, timeout=10) as resp:
            return json.loads(resp.read().decode("utf-8"))

    def card(self) -> dict:
        import urllib.request
        url = f"{self.endpoint}/card"
        with urllib.request.urlopen(url, timeout=10) as resp:
            return json.loads(resp.read().decode("utf-8"))

    def __repr__(self):
        return f"AgentClient(endpoint={self.endpoint!r})"
