/**
 * @file LocalClient.h
 * @author apio (cloudapio.eu)
 * @brief UNIX local domain client class.
 *
 * @copyright Copyright (c) 2023, the Luna authors.
 *
 */

#pragma once
#include <luna/OwnedPtr.h>
#include <luna/StringView.h>

namespace os
{
    /**
     * @brief A client used to connect to a local server socket.
     */
    class LocalClient
    {
      public:
        /**
         * @brief Create a new client object and connect it to a local server.
         *
         * @param path The path of the server socket to connect to.
         * @param blocking Whether the client should block if no data is available and recv() is called.
         * @return Result<OwnedPtr<LocalClient>> An error, or a new client object.
         */
        static Result<OwnedPtr<LocalClient>> connect(StringView path, bool blocking);

        /**
         * @brief Return the underlying socket file descriptor used by this object.
         *
         * @return int The file descriptor.
         */
        int fd() const
        {
            return m_fd;
        }

        /**
         * @brief Read arbitrary data from the server. The call will block if there is no data and this object has not
         * been created as non-blocking.
         *
         * @param buf The buffer to read data into.
         * @param length The maximum amount of bytes to read.
         * @return Result<usize> An error, or the number of bytes read.
         */
        Result<usize> recv(u8* buf, usize length);

        /**
         * @brief Read an object from the server. The call will block if there is no data and this object has not been
         * created as non-blocking.
         *
         * @tparam T The type of the object.
         * @param out A reference to the object to read data into.
         * @return Result<void> Whether the operation succeded.
         */
        template <typename T> Result<void> recv_typed(T& out)
        {
            TRY(recv((u8*)&out, sizeof(T)));
            return {};
        }

        /**
         * @brief Send arbitrary data to the server.
         *
         * @param buf The buffer to send data from.
         * @param length The amount of bytes to send.
         * @return Result<usize> An error, or the number of bytes actually sent.
         */
        Result<usize> send(const u8* buf, usize length);

        /**
         * @brief Send an object to the server.
         *
         * @tparam T The type of the object.
         * @param out A reference to the object to send data from.
         * @return Result<void> Whether the operation succeded.
         */
        template <typename T> Result<void> send_typed(const T& out)
        {
            TRY(send((const u8*)&out, sizeof(T)));
            return {};
        }

        /**
         * @brief Disconnect from the attached server.
         *
         * This will make any further reads on this connection return ECONNRESET, and will make this object invalid.
         */
        void disconnect();

        ~LocalClient();

      private:
        int m_fd;
    };
}