#ifndef BELT_JUNCTION_CONTROLLER_HPP_
#define BELT_JUNCTION_CONTROLLER_HPP_

#include <Controller/InventoryController/InventoryController.hpp>
#include <RemoteDataComponent/RemoteDataComponent.hpp>
#include <Controller/Controller.hpp>
#include <Entity/PhysicsEntity/CameraEntity/Player/Player.hpp>
#include <Machine/MBeltJunction/MBeltJunction.hpp>
#include <MachineComponent/DataCableComponent/DataCableComponent.hpp>
#include <memory>

/**
 * @brief Controller for the belt junction.
 */
class BeltJunctionController final : public InventoryController
{
private:
    static constexpr int rulesNaturalHeight = 100;
    static constexpr int rulesNaturalWidth = 150;

    std::shared_ptr<MBeltJunction> junction;

    int ruleUpdateCounter = -1;
    std::vector<MBeltJunction::Rule> rules;

    int statUpdateCounter = -1;
    MBeltJunction::Stats stats;

    Command<
        uint32_t,
        uint32_t,
        std::vector<MBeltJunction::Rule>,
        uint32_t,
        MBeltJunction::Stats
    > updateJunctionState;
    Command<uint32_t, uint32_t> addRule;
    Command<uint32_t, uint32_t> deleteRule;
    Command<uint32_t, uint32_t, std::optional<DataLink::Channel>> setRuleControlChannel;
    Command<uint32_t, uint32_t, MBeltJunction::OutputBelt> setRuleOutputBelt;
    Command<uint32_t, uint32_t, uint32_t> setRuleInterval;
    Command<uint32_t, uint32_t, ItemStack> setRuleRefStack;
    Command<uint32_t, uint32_t, uint32_t> swapRules;

    Widget* makeFilterTab();
    Widget* makeOutputBeltPicker(MBeltJunction::OutputBelt &belt, std::function<void()> onChanged);
    Widget* makeRule(size_t index);
    Widget* makeRuleList();

    Widget* makeStatsTab();
    Widget* makeItemStatsList();
    Widget* makeItemStat(size_t index);

public:
    BeltJunctionController(ControllerChannel &channel);

    void onConnect(std::shared_ptr<Machine> beltJunctionMachine);

    virtual Widget* getRightPanel() override;
    virtual bool isBusy() override;
    virtual void update() override;
};

#endif