import sys, logging, asyncio, json
from typing import Any, Self

from ._core import JsonRpcConnection
from ._exceptions import *

logger = logging.getLogger(__name__)


class JsonRpcStdioConnection(JsonRpcConnection):
    def __init__(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
        super().__init__()
        self._reader = reader
        self._writer = writer

    @classmethod
    async def connect(cls, **kwargs) -> Self:
        """Creates a JSON-RPC connection over stdin/stdout."""
        loop = asyncio.get_running_loop()
        reader = asyncio.StreamReader()
        await loop.connect_read_pipe(lambda: asyncio.StreamReaderProtocol(reader), sys.stdin.buffer)
        transport, protocol = await loop.connect_write_pipe(asyncio.BaseProtocol, sys.stdout.buffer)
        writer = asyncio.StreamWriter(transport, protocol, reader, loop)
        connection = cls(reader, writer, **kwargs)
        connection._start_read_loop()
        return connection

    @classmethod
    async def serve(cls, **kwargs):
        """Not applicable for stdio — use connect() instead."""
        raise NotImplementedError("stdio connections do not support serve(); use connect()")

    async def _send_bytes(self, data: bytes) -> None:
        self._writer.write(data + b"\n")
        await self._writer.drain()

    async def _cleanup(self) -> None:
        try:
            self._writer.close()
            await self._writer.wait_closed()
        except OSError:
            pass

    async def _read_loop(self) -> None:
        try:
            while True:
                line = await self._reader.readline()
                if line.strip() == b"":
                    logger.debug("stdio stream closed")
                    break
                obj = json.loads(line)
                await self._handle_incoming_message(obj)
        except Exception:
            logger.error("Error in stdio read loop", exc_info=True)
        finally:
            await self.close()


__all__ = ["JsonRpcStdioConnection"]
