"""Fake socket interface for {{ interface_name }}.

Simulated socket for testing without a network connection.

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

import logging
import time
from typing import Any

logger = logging.getLogger(__name__)


class {{ interface_name | pascal_case }}FakeInterface:
    """Fake socket interface for testing {{ interface_name }} without a network.

    Simulates TCP/UDP socket behavior with configurable responses.

    Example:
        >>> interface = {{ interface_name | pascal_case }}FakeInterface()
        >>> interface.set_response(b"OK\\n")
        >>> interface.connect()
        >>> interface.send(b"HELLO\\n")
        >>> response = interface.receive()
        >>> assert response == b"OK\\n"
    """

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

        Args:
            host: Simulated remote host.
            port: Simulated remote port.
            protocol: Protocol type, either "tcp" or "udp".
            timeout: Simulated timeout.
            simulated_latency: Artificial delay for each operation in seconds.
            **kwargs: Additional configuration (ignored).
        """
        self._host = host
        self._port = port
        self._protocol = protocol.lower()
        self._timeout = timeout
        self._simulated_latency = simulated_latency
        self._is_connected = False
        self._send_buffer: list[bytes] = []
        self._receive_buffer = b""
        self._operation_count = 0

        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

    @property
    def operation_count(self) -> int:
        """Get the total number of send/receive operations performed."""
        return self._operation_count

    @property
    def send_history(self) -> list[bytes]:
        """Get a copy of the send history."""
        return list(self._send_buffer)

    def set_response(self, data: bytes) -> None:
        """Set the data that will be returned by receive.

        Args:
            data: Bytes to enqueue in the receive buffer.
        """
        self._receive_buffer = data

    def connect(self) -> None:
        """Simulate establishing a socket connection."""
        time.sleep(self._simulated_latency)
        self._is_connected = True
        logger.info(f"[FAKE] Connected to {self._host}:{self._port} via {self._protocol.upper()}")

    def disconnect(self) -> None:
        """Simulate closing the socket connection."""
        if self._is_connected:
            self._is_connected = False
            logger.info(f"[FAKE] Disconnected from {self._host}:{self._port}")

    def send(self, data: bytes) -> int:
        """Simulate sending 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.")
        time.sleep(self._simulated_latency)
        self._send_buffer.append(data)
        self._operation_count += 1
        return len(data)

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

        Args:
            size: Maximum number of bytes to receive.

        Returns:
            Bytes from the internal receive buffer.

        Raises:
            RuntimeError: If not connected.
        """
        if not self._is_connected:
            raise RuntimeError("Socket not connected. Call connect() first.")
        time.sleep(self._simulated_latency)
        self._operation_count += 1
        result = self._receive_buffer[:size]
        self._receive_buffer = self._receive_buffer[size:]
        return result

    def query(self, command: str, terminator: str = "\n") -> str:
        """Simulate query (send command, then receive 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()

    def reset(self) -> None:
        """Reset all internal state for test isolation."""
        self._send_buffer = []
        self._receive_buffer = b""
        self._operation_count = 0
