#pragma once

#include <cstdint>
#include <functional>
#include <map>
#include <string>

/**
 * @brief Felix-client-thread interface class.
 * @note Use it as a virtual class.
*/
class FelixClientThreadInterface {

public:

    /**
     * @brief Data callback executed by the event loop (network reactor) thread.
     * @attention Blocking in this function blocks the eventloop, return as soon as possible.
     *
     * @param fid The fid (e-link identifier) from which the message originates
     * @param data Pointer to data message
     * @param size Size in bytes of the received message
     * @param status One-byte field used to report errors in the message, see felix_client_status.h
     */
    typedef std::function<void (uint64_t fid, const uint8_t* data, size_t size, uint8_t status)> OnDataCallback;

    /**
     * @brief Callback executed by event loop thread at start.
     */
    typedef std::function<void ()> OnInitCallback;

    /**
     * @brief Callback reporting that a connection has been established.
     * @param fid The fid for which the connection is up.
     */
    typedef std::function<void (uint64_t fid)> OnConnectCallback;

    /**
     * @brief Callback reporting that a connection has been closed.
     * @param fid The fid for which the connection is down.
     */
    typedef std::function<void (uint64_t fid)> OnDisconnectCallback;

    /**
     * @brief User function to be passed to exec() for execution in the event loop.
     */
    typedef std::function<void ()> UserFunction;


    /**
     * @brief User timer function to be passed to callback_on_user_timer() for execution in the event loop.
     */
    typedef std::function<void ()> OnUserTimerCallback;

    /**
     * Data structure to hold configuration parameters
     * defined in felix_client_properties header.
     */
    typedef std::map<std::string, std::string> Properties;

    /**
     * Data structure that includes both configuration parameters
     * and pointers to callbacks.
     */
    struct Config {
        OnDataCallback on_data_callback;
        OnInitCallback on_init_callback;
        OnConnectCallback on_connect_callback;
        OnDisconnectCallback on_disconnect_callback;
        Properties property;
    };

    virtual ~FelixClientThreadInterface() {};

    /**
     * @brief Function to send a message to a remote fid.
     *
     * This function takes care of establishing a connection to the remote endpoint
     * if not already available. The send request is passed to the eventloop thread.
     * The caller thread is blocked until the send operation is completed.
     *
     * @param fid The fid, typically published by felix-toflx, to which the message is addressed to.
     * @param data Pointer to message
     * @param size Size of message
     * @param flush For buffered mode, indicates if the buffer shall be sent right away.
     *
     * @throws FelixClientException if the subscription fails.
     */
    [[deprecated("Use send_data(uint64_t, std::span<const uint8_t>, bool) instead")]]
    virtual void send_data(uint64_t fid, const uint8_t* data, size_t size, bool flush) = 0;


    /**
     * @brief Subscribe to a given fid.
     *
     * The remote endpoint is identified from felix-bus and a connection is
     * established if not already present. The creation of sockets and network
     * buffers is performed in the event loop thread. This function blocks the
     * caller thread until an attempt to establish the connection has started
     * or the subscription message is sent to the remote endpoint.
     *
     * If a timeout is specified using the FELIX_CLIENT_TIMEOUT property,
     * the function blocks until the subscription succeds or the timeout expires.
     * A successful subscription will be either way acknowledge by the
     * OnConnectCallback callback. A subscription is considered successful if
     * the request was received by the remote endpoint.
     *
     * @param fid The fid to subscribe to.
     * @throws FelixClientException if the send operation fails.
     */
    [[deprecated("Use subscribe(uint64_t, std::chrono::milliseconds) or subscribe_nb(uint64_t) instead")]]
    virtual void subscribe(uint64_t fid) = 0;


    /**
     * @brief Unsubscribe from a given fid.
     *
     * Similar to subscribe(), it blocks until the unsubscribe request is sent
     * to the remote endpoint. Since this is an asynchronous operation, it is
     * not guaranteed that no data will arrive for this FID after the
     * unsubscribe.
     *
     * @note If the application unsubscribed from all fids it is subscribe to, the
     * remote endpoint will close the connection.
     * @param fid The fid to unsubscribe from.
     * @throws FelixClientException if the unsubscription fails.
     */
    [[deprecated("Use unsubscribe(const uint64_t, std::chrono::milliseconds) or subscribe_nb(const uint64_t) instead")]]
    virtual void unsubscribe(uint64_t fid) = 0;


    /**
     * @brief Execute a function in the eventloop thread
     *
     * This function allows to execute a user function in the event loop thread.
     *
     * @param user_function function pointer to user function.
     */
    virtual void exec(const UserFunction &user_function) = 0;
};
