
#ifndef COMPONENT_H
#define COMPONENT_H

#include <WString.h>
#include <ArduinoLog.h>

#include <enums.h>
#include <constants.h>
#include <error_codes.h>

#include "macros.h"
#include "types.h"
#include "ModbusValue.h"

class Bridge;

/**
 * @brief The Component class represents a generic component.
 */
class Component : virtual public ModbusGateway
{
public:
    /**
     * @brief The default run flags for a component.
     */
    static const int COMPONENT_DEFAULT = 1 << OBJECT_RUN_FLAGS::E_OF_LOOP | 1 << OBJECT_RUN_FLAGS::E_OF_SETUP;

    /**
     * @brief The default ID for a component.
     */
    static const int COMPONENT_NO_ID = 0;

    /**
     * @brief Default constructor for the Component class.
     */
    Component() : name("NO_NAME"), id(0),
                  flags(OBJECT_RUN_FLAGS::E_OF_NONE),
                  nFlags(OBJECT_NET_CAPS::E_NCAPS_NONE) {}

    /**
     * @brief Constructor for the Component class with a specified name.
     * @param _name The name of the component.
     */
    Component(String _name) : name(_name), id(COMPONENT_NO_ID),
                              flags(OBJECT_RUN_FLAGS::E_OF_NONE),
                              nFlags(OBJECT_NET_CAPS::E_NCAPS_NONE) {}

    /**
     * @brief Constructor for the Component class with a specified name and ID.
     * @param _name The name of the component.
     * @param _id The ID of the component.
     */
    Component(String _name, short _id) : name(_name),
                                         id(_id),
                                         flags(OBJECT_RUN_FLAGS::E_OF_NONE),
                                         nFlags(OBJECT_NET_CAPS::E_NCAPS_NONE) {}

    /**
     * @brief Constructor for the Component class with a specified name, ID, and flags.
     * @param _name The name of the component.
     * @param _id The ID of the component.
     * @param _flags The run flags for the component.
     */
    Component(String _name, short _id, int _flags) : name(_name),
                                                     id(_id),
                                                     flags(_flags),
                                                     nFlags(OBJECT_NET_CAPS::E_NCAPS_NONE)
    {
    }

    /**
     * @brief Constructor for the Component class with a specified name, ID, flags, and owner.
     * @param _name The name of the component.
     * @param _id The ID of the component.
     * @param _flags The run flags for the component.
     * @param _owner The owner of the component.
     */
    Component(String _name, short _id, int _flags, Component *_owner) : name(_name),
                                                                        id(_id),
                                                                        flags(_flags),
                                                                        owner(_owner),
                                                                        nFlags(OBJECT_NET_CAPS::E_NCAPS_NONE) {}

    /**
     * @brief Destructor for the Component class.
     */
    ~Component() {}

    /**
     * @brief Virtual function to destroy the component.
     * @return The error code indicating the success or failure of the operation.
     */
    virtual short destroy() { return E_OK; }

    /**
     * @brief Virtual function to debug the component.
     * @param stream The stream to output the debug information to.
     * @return The error code indicating the success or failure of the operation.
     */
    virtual short debug() { return E_OK; }

    /**
     * @brief Virtual function to debug the component.
     * @param stream The stream to output the debug information to.
     * @return The error code indicating the success or failure of the operation.
     */
    virtual short debug(short val0, short val1) { return E_OK; }

    /**
     * @brief Virtual function to display information about the component.
     * @param stream The stream to output the information to.
     * @return The error code indicating the success or failure of the operation.
     */
    virtual short info() { return E_OK; }

    /**
     * @brief Virtual function to display information about the component.
     * @param stream The stream to output the information to.
     * @return The error code indicating the success or failure of the operation.
     */
    virtual short info(short val0, short val1) { return E_OK; }

    /**
     * @brief Virtual function to set up the component.
     * @return The error code indicating the success or failure of the operation.
     */
    virtual short setup() { return E_OK; }

    /**
     * @brief Virtual function to run the component in a loop.
     * @return The error code indicating the success or failure of the operation.
     */
    virtual short loop() { return E_OK; }

    /**
     * @brief Checks if the component has a specific flag.
     * @param flag The flag to check.
     * @return True if the component has the flag, false otherwise.
     */
    bool hasFlag(byte flag)
    {
        return TEST(flags, flag);
    }

    /**
     * @brief Sets a specific flag for the component.
     * @param flag The flag to set.
     */
    void setFlag(byte flag)
    {
        SBI(flags, flag);
    }

    /**
     * @brief Clears a specific flag for the component.
     * @param flag The flag to clear.
     */
    void clearFlag(byte flag)
    {
        CBI(flags, flag);
    }

    /**
     * @brief Enables the component.
     */
    void enable()
    {
        clearFlag(OBJECT_RUN_FLAGS::E_OF_DISABLED);
    }

    /**
     * @brief Disables the component.
     */
    void disable()
    {
        setFlag(OBJECT_RUN_FLAGS::E_OF_DISABLED);
    }

    /**
     * @brief Checks if the component is enabled.
     * @return True if the component is enabled, false otherwise.
     */
    bool enabled()
    {
        return !hasFlag(OBJECT_RUN_FLAGS::E_OF_DISABLED);
    }

    /**
     * @brief The name of the component.
     */
    String name;

    /**
     * @brief The ID of the component.
     */
    const short id;

    /**
     * @brief The run flags for the component.
     */
    int flags;

    /**
     * @brief The network capabilities of the component.
     */
    int nFlags;

    /**
     * @brief The owner of the component.
     */
    Component *owner;

    /**
     * @brief The current time in milliseconds.
     */
    millis_t now;

    /**
     * @brief The last tick time in milliseconds.
     */
    millis_t last;

    //////////////////////////////////////////
    //
    //  Messaging
    //  @todo: extract to a separate class

    /**
     * @brief Handles incoming messages.
     *
     * This function is called when a message is received by the component.
     * It processes the message and returns a short value indicating the status of the operation.
     *
     * @param id The ID of the message.
     * @param verb The type of operation to be performed.
     * @param flags The flags associated with the message.
     * @param user A pointer to user-defined data.
     * @param src The source component that sent the message.
     * @return A short value indicating the status of the operation.
     */
    virtual short onMessage(int id, E_CALLS verb, E_MessageFlags flags, const void *user, Component *src)
    {
        return E_OK;
    }

    virtual short onError(short error) { return E_OK; }
    virtual short onResponse(short error) { return E_OK; }
    virtual short onRawResponse(short size, uint8_t rxBuffer[]) { return E_OK; }

    //////////////////////////////////////////
    //
    //  Binding
    //  @todo: extract to a separate class

    /**
     * Registers methods for the component with the specified bridge.
     * This method should be overridden by derived classes to provide custom method registration logic.
     *
     * @param bridge The bridge to register methods with.
     * @return The status code indicating the success or failure of the method registration.
     */
    virtual short onRegisterMethods(Bridge *bridge);
};

/**
 * @brief Function pointer type for component member functions.
 */
typedef short (Component::*ComponentFnPtr)(short, short);

/**
 * @brief Function pointer type for component member functions with variable arguments.
 */
typedef short (Component::*ComponentVarArgsFnPtr)(...);

typedef short (Component::*ComponentRxFn)(short size, uint8_t rxBuffer[]);

#endif
