"""{{ interface_description }}

Serial port communication interface using pySerial patterns.

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

import logging
from typing import Any, Optional

logger = logging.getLogger(__name__)


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

    Provides serial communication with open/close/read/write/flush operations.

    Example:
        >>> interface = {{ interface_name | pascal_case }}Interface(port="/dev/ttyUSB0")
        >>> interface.open()
        >>> interface.write(b"*IDN?\\n")
        >>> response = interface.read()
        >>> interface.close()
    """

    def __init__(
        self,
        port: str = "/dev/ttyUSB0",
        baudrate: int = 9600,
        timeout: float = 1.0,
        **kwargs: Any,
    ) -> None:
        """Initialize the serial interface.

        Args:
            port: Serial port path (e.g., /dev/ttyUSB0, COM3).
            baudrate: Communication baud rate.
            timeout: Read timeout in seconds.
            **kwargs: Additional serial settings.
        """
        self._port = port
        self._baudrate = baudrate
        self._timeout = timeout
        self._config = kwargs
        self._connection: Any = None
        self._is_open = False

    @property
    def is_open(self) -> bool:
        """Check if the serial port is open."""
        return self._is_open

    def open(self) -> None:
        """Open the serial port.

        Raises:
            ConnectionError: If the port cannot be opened.
        """
        logger.info(f"Opening serial port {self._port} at {self._baudrate} baud...")

        # TODO: Implement actual serial connection
        # import serial
        # self._connection = serial.Serial(
        #     port=self._port,
        #     baudrate=self._baudrate,
        #     timeout=self._timeout,
        #     **self._config,
        # )

        self._is_open = True
        logger.info(f"Serial port {self._port} opened")

    def close(self) -> None:
        """Close the serial port."""
        if self._is_open:
            logger.info(f"Closing serial port {self._port}...")

            # TODO: Close actual connection
            # if self._connection:
            #     self._connection.close()

            self._is_open = False
            self._connection = None
            logger.info(f"Serial port {self._port} closed")

    def write(self, data: bytes) -> int:
        """Write data to the serial port.

        Args:
            data: Bytes to write.

        Returns:
            Number of bytes written.

        Raises:
            RuntimeError: If port is not open.
        """
        if not self._is_open:
            raise RuntimeError("Serial port not open. Call open() first.")

        logger.debug(f"Writing {len(data)} bytes to {self._port}")

        # TODO: Implement actual write
        # return self._connection.write(data)

        return len(data)

    def read(self, size: int = 1024) -> bytes:
        """Read data from the serial port.

        Args:
            size: Maximum number of bytes to read.

        Returns:
            Bytes read from the port.

        Raises:
            RuntimeError: If port is not open.
        """
        if not self._is_open:
            raise RuntimeError("Serial port not open. Call open() first.")

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

        # TODO: Implement actual read
        # return self._connection.read(size)

        return b""

    def readline(self) -> bytes:
        """Read a line from the serial port.

        Returns:
            Bytes read until newline or timeout.

        Raises:
            RuntimeError: If port is not open.
        """
        if not self._is_open:
            raise RuntimeError("Serial port not open. Call open() first.")

        # TODO: Implement actual readline
        # return self._connection.readline()

        return b""

    def flush(self) -> None:
        """Flush the serial port buffers.

        Raises:
            RuntimeError: If port is not open.
        """
        if not self._is_open:
            raise RuntimeError("Serial port not open. Call open() first.")

        # TODO: Implement actual flush
        # self._connection.flush()

        logger.debug(f"Flushed serial port {self._port}")

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

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

        Returns:
            Response string from the device.

        Raises:
            RuntimeError: If port is not open.
        """
        if not self._is_open:
            raise RuntimeError("Serial port not open. Call open() first.")

        self.write((command + terminator).encode())
        response = self.readline()
        return response.decode().strip()
