#ifndef MACHINE_COMPONENT_HPP_
#define MACHINE_COMPONENT_HPP_

#include <ItemStack/ItemStack.hpp>
#include <vector>
#include <cstdint>
#include <cstddef>

class Machine;

/**
 * @brief Base class for machine components.
 *
 * Each child class must have a static field called `tagName` which will be a string
 * of the form "mod:tag", for example "main:electricComponent".
 */
class MachineComponent
{
protected:
    Machine &machine;

public:
    virtual ~MachineComponent() = default;

    MachineComponent(Machine &machine);

    MachineComponent(const MachineComponent &&) = delete;
    MachineComponent(MachineComponent &&) = delete;

    MachineComponent& operator=(const MachineComponent&) = delete;
    MachineComponent& operator=(MachineComponent&&) = delete;

    /**
     * @brief Serialize the state of this component.
     * 
     * @param outBytes The vector to append the state to.
     */
    virtual void serializeState(std::vector<uint8_t> &outBytes) = 0;

    /**
     * @brief Deserialize the state of this component.
     * 
     * @param bytes The bytes.
     * @param size The number of bytes.
     */
    virtual void deserializeState(const uint8_t *bytes, size_t size) = 0;

    /**
     * @brief Returns true if the machine is ready (fully loaded).
     *
     * By default always returns true.
     */
    virtual bool isReady();

    /**
     * @brief Called when the machine is being removed.
     *
     * Does nothing by default.
     */
    virtual void onRemoving();

    /**
     * @brief Called just before an update of the machine.
     *
     * Does nothing by default.
     */
    virtual void onPreUpdate();

    /**
     * @brief Called just after an update of the machine.
     * 
     * Does nothing by default.
     */
    virtual void onPostUpdate();

    /**
     * @brief Serialize this machine's config.
     * 
     * @param consumedItems You can push items to consume for this config here.
     * @param data Output the config of this machine here.
     */
    virtual void saveConfig(std::vector<ItemStack> &consumedItems, std::vector<uint8_t> &data);

    /**
     * @brief Deserialize this machine's config.
     * 
     * @param data The config to deserialize.
     * @param consumed `true` if the config's required items were consumed; otherwise load only non-item config.
     */
    virtual void loadConfig(const std::vector<uint8_t> &data, bool consumed);
};

#endif