"""{{ interface_description }}

TCP/UDP socket communication interface.

Generated by: madsci new comm --template comm/socket
Template version: {{ template_version }}
"""

import logging
from typing import Any, Optional

logger = logging.getLogger(__name__)


class {{ interface_name | pascal_case }}Interface:
    """Socket interface for {{ interface_name }}.

    Provides TCP or UDP socket communication with connect/disconnect/send/receive
    operations.

    Example:
        >>> interface = {{ interface_name | pascal_case }}Interface(host="192.168.1.100", port=5000)
        >>> interface.connect()
        >>> interface.send(b"HELLO\\n")
        >>> response = interface.receive()
        >>> interface.disconnect()
    """

    def __init__(
        self,
        host: str = "127.0.0.1",
        port: int = 5000,
        protocol: str = "tcp",
        timeout: float = 5.0,
        **kwargs: Any,
    ) -> None:
        """Initialize the socket interface.

        Args:
            host: Remote host address.
            port: Remote port number.
            protocol: Protocol type, either "tcp" or "udp".
            timeout: Socket timeout in seconds.
            **kwargs: Additional socket options.
        """
        self._host = host
        self._port = port
        self._protocol = protocol.lower()
        self._timeout = timeout
        self._config = kwargs
        self._socket: Any = None
        self._is_connected = False

        if self._protocol not in ("tcp", "udp"):
            raise ValueError(f"Unsupported protocol: {self._protocol}. Use 'tcp' or 'udp'.")

    @property
    def is_connected(self) -> bool:
        """Check if the socket is connected."""
        return self._is_connected

    def connect(self) -> None:
        """Establish the socket connection.

        Raises:
            ConnectionError: If the connection cannot be established.
        """
        logger.info(
            f"Connecting to {self._host}:{self._port} via {self._protocol.upper()}..."
        )

        # TODO: Implement actual socket connection
        # import socket
        # if self._protocol == "tcp":
        #     self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # else:
        #     self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        # self._socket.settimeout(self._timeout)
        # self._socket.connect((self._host, self._port))

        self._is_connected = True
        logger.info(f"Connected to {self._host}:{self._port}")

    def disconnect(self) -> None:
        """Close the socket connection."""
        if self._is_connected:
            logger.info(f"Disconnecting from {self._host}:{self._port}...")

            # TODO: Close actual socket
            # if self._socket:
            #     self._socket.close()

            self._is_connected = False
            self._socket = None
            logger.info(f"Disconnected from {self._host}:{self._port}")

    def send(self, data: bytes) -> int:
        """Send data over the socket.

        Args:
            data: Bytes to send.

        Returns:
            Number of bytes sent.

        Raises:
            RuntimeError: If not connected.
        """
        if not self._is_connected:
            raise RuntimeError("Socket not connected. Call connect() first.")

        logger.debug(f"Sending {len(data)} bytes to {self._host}:{self._port}")

        # TODO: Implement actual send
        # return self._socket.send(data)

        return len(data)

    def receive(self, size: int = 4096) -> bytes:
        """Receive data from the socket.

        Args:
            size: Maximum number of bytes to receive.

        Returns:
            Bytes received from the socket.

        Raises:
            RuntimeError: If not connected.
        """
        if not self._is_connected:
            raise RuntimeError("Socket not connected. Call connect() first.")

        logger.debug(f"Receiving up to {size} bytes from {self._host}:{self._port}")

        # TODO: Implement actual receive
        # return self._socket.recv(size)

        return b""

    def query(self, command: str, terminator: str = "\n") -> str:
        """Send a command string and receive the response.

        Args:
            command: Command string to send.
            terminator: Line terminator to append.

        Returns:
            Decoded and stripped response string.

        Raises:
            RuntimeError: If not connected.
        """
        if not self._is_connected:
            raise RuntimeError("Socket not connected. Call connect() first.")

        self.send((command + terminator).encode())
        response = self.receive()
        return response.decode().strip()
