#ifndef FLUID_LINK_HPP_
#define FLUID_LINK_HPP_

#include <vector>
#include <memory>
#include <optional>
#include <string>

#include <WorldComponent/Wiring/Wiring.hpp>
#include <Machine/Machine.hpp>
#include <Side/Side.hpp>
#include <ChunkHandle/ChunkHandle.hpp>

/**
 * @brief Represents a link between a machine port and other ports.
 */
class FluidLink
{
private:
    struct Endpoint
    {
        std::weak_ptr<Machine> machine;
        Side side;
    };

    LocalWorld *world = nullptr;
    std::vector<Endpoint> endpoints;

public:
    static std::shared_ptr<FluidLink> dummyLink;
    const glm::ivec3 pos = glm::ivec3(0, 0, 0);
    const Side side = Side(0);

    FluidLink() = default;

    /**
     * @brief Construct a new fluid link from the specified data.
     */
    FluidLink(LocalWorld &world, std::shared_ptr<WorldGridNode> node, std::vector<Wiring::Port> &ports, size_t startingPort);

    /**
     * @brief Get the fluid link from the specified machine's side.
     * 
     * @param machine The machine requesting a link.
     * @param side The side of the machine where we are searching from.
     */
    static std::shared_ptr<FluidLink> get(Machine &machine, Side side);

    /**
     * @brief Return the default fluid to pull, if any.
     */
    std::optional<std::string> getDefaultFluid();

    /**
     * @brief Try to pull the specified amount of fluid.
     * 
     * @param fluidName The fluid name to pull (e.g. "main:water").
     * @param amount The maximum amount to pull (ml).
     * @return The amount actually pulled (ml).
     */
    int pullFluid(std::string fluidName, int amount);

    /**
     * @brief Try to push the specified amount of fluid.
     * 
     * @param fluidName The fluid name to push (e.g. "main:water").
     * @param amount The maximum amount to push (ml).
     * @return The amount successfully pushed (ml).
     */
    int pushFluid(std::string fluidName, int amount);
};

#endif