# Copyright 2023 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import asyncio
import logging
from collections.abc import Buffer

import fuchsia_controller_py as fc

from ._ipc import GlobalHandleWaker, HandleWaker

_LOGGER: logging.Logger = logging.getLogger(__name__)


class AlreadyReadingAll(Exception):
    def __init__(self) -> None:
        super().__init__("This socket is already doing a read-all operation.")


class AsyncSocket:
    """Represents an async socket.

    In 99% of cases it is recommended to use this instead of the standard fuchsia-controller Socket
    object. This has built-in support for handling waits.

    In the remaining 1% of cases it may be useful for the user to do a one-off attempt at reading a
    socket directly and immediately exiting in the event that FC_ERR_SHOULD_WAIT is encountered.
    Such a case would likely involve adding some custom behavior to existing async code, like
    registering custom wakers. Another case would be where the user is _only_ writing to the socket,
    as writes in AsyncSocket are also synchronous and wrap Socket.write directly.

    Args:
        socket: The socket which will be asynchronously readable.
        waker: (Optional) the HandleWaker implementation (defaults to GlobalHandleWaker).

    Raises:

    If you are running this socket in a task using `read_all()` be sure there is
    only one instance of `read_all()` running, else this will raise an exception
    in the case where one attempts to run `read()` or `read_all()` after this
    has been initiated.

    Keep in mind that if you run `read_all()` and place it on a task in the
    executor, and you do not yield to the executor, and then attempt to run
    `read_all()`, then it will be the task itself that will fail, because the
    read invocation will be reached before yielding to the async task, so you
    cannot solely rely on this to catch potential deadlocks.
    """

    waker: HandleWaker

    def __init__(self, socket: fc.Socket, waker: HandleWaker | None = None):
        self.socket = socket
        if waker is None:
            self.waker = GlobalHandleWaker()
        else:
            self.waker = waker
        self._read_all_lock = asyncio.Lock()

    def __del__(self) -> None:
        self.socket.close()

    def _invariant_check(self) -> None:
        """Checks to make sure we're not already in the middle of a read-all
        invocation."""
        if self._read_all_lock.locked():
            raise AlreadyReadingAll()

    async def read(self) -> bytes:
        """Attempts to read off of the socket.

        Returns:
            bytes read from the socket.

        Raises:
            FcTransportStatus exception outlining the specific failure of the underlying handle.

            AlreadyReadAll exception if `read_all()` is being invoked elsewhere
            asynchronously.
        """
        self._invariant_check()
        return await self._read()

    async def _read(self) -> bytes:
        _LOGGER.debug("Doing read of socket: %s", self.socket)
        with self.waker.registration(
            self.socket, name=f"AsyncSocket {self.socket}"
        ):
            while True:
                try:
                    return self.socket.read()
                except fc.FcTransportStatus as e:
                    if e.args[0] != fc.FcTransportStatus.FC_ERR_SHOULD_WAIT:
                        raise e
                    _LOGGER.debug(
                        f"Received wait signal for socket: {self.socket}"
                    )
                _LOGGER.debug(f"Awaiting socket wake for socket: {self.socket}")
                await self.waker.wait_ready(self.socket)

    async def read_all(self) -> bytearray:
        """Attempts to read all data on the socket until it is closed.

        Returns:
            All bytes read on the socket.

        Raises:
            Any FC errors encountered besides FC_ERR_SHOULD_WAIT or
            FC_ERR_FDOMAIN.

            AlreadyReadAll exception if `read_all()` is being invoked elsewhere
            asynchronously.
        """
        self._invariant_check()
        output = bytearray()
        async with self._read_all_lock:
            while True:
                try:
                    output.extend(await self._read())
                except fc.FcTransportStatus as status:
                    _LOGGER.debug(
                        f"Socket {self.socket} caught exception: {status}"
                    )
                    err_code = status.code()
                    if err_code != fc.FcTransportStatus.FC_ERR_FDOMAIN:
                        raise status
                    break
            self.socket.close()
            return output

    def write(self, buf: Buffer) -> None:
        """Does a blocking write on the socket.

        This is identical to calling the write function on the socket itself.

        Args:
            buf: The array of bytes (read-only) to write to the socket.

        Raises:
            FcTransportStatus exception on failure of the underlying handle.
        """
        self.socket.write(buf)
